Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Commit c30abfe

Browse files
committed
Add CLI Tests
1 parent 5aa125a commit c30abfe

File tree

4 files changed

+82
-60
lines changed

4 files changed

+82
-60
lines changed

src/codegate/cli.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ def serve(
260260
ca_key: Optional[str],
261261
server_cert: Optional[str],
262262
server_key: Optional[str],
263-
force_certs: bool,
264263
) -> None:
265264
"""Start the codegate server."""
266265
try:
@@ -292,7 +291,6 @@ def serve(
292291
ca_key=ca_key,
293292
server_cert=server_cert,
294293
server_key=server_key,
295-
force_certs=force_certs,
296294
db_path=db_path,
297295
)
298296

@@ -501,7 +499,7 @@ def generate_certs(
501499
click.echo("Make sure to add the new CA certificate to the operating system trust store.")
502500
else:
503501
click.echo("Certificates already exist. Skipping generation...")
504-
sys.exit(0)
502+
505503

506504
def main() -> None:
507505
"""Main entry point for the CLI."""

src/codegate/pipeline/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def get_last_user_message_idx(request: ChatCompletionRequest) -> int:
187187
if request.get("messages") is None:
188188
return -1
189189

190-
for idx, message in reversed(list(enumerate(request['messages']))):
190+
for idx, message in reversed(list(enumerate(request["messages"]))):
191191
if message.get("role", "") == "user":
192192
return idx
193193

src/codegate/pipeline/codegate_context_retriever/codegate.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ async def process(
110110
return PipelineResult(request=request)
111111

112112
# Look for matches in vector DB using list of packages as filter
113-
searched_objects = await self.get_objects_from_search(
114-
user_messages, ecosystem, packages
115-
)
113+
searched_objects = await self.get_objects_from_search(user_messages, ecosystem, packages)
116114

117115
logger.info(
118116
f"Found {len(searched_objects)} matches in the database",
@@ -149,4 +147,3 @@ async def process(
149147
message["content"] = context_msg
150148

151149
return PipelineResult(request=new_request, context=context)
152-

tests/test_cli.py

Lines changed: 79 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
"""Tests for the server module."""
22

33
import os
4-
from unittest.mock import MagicMock, patch, AsyncMock
4+
from pathlib import Path
5+
from unittest.mock import AsyncMock, MagicMock, patch
56

67
import pytest
8+
from click.testing import CliRunner
79
from fastapi.middleware.cors import CORSMiddleware
810
from fastapi.testclient import TestClient
911
from httpx import AsyncClient
12+
from uvicorn.config import Config as UvicornConfig
1013

1114
from codegate import __version__
1215
from codegate.pipeline.factory import PipelineFactory
1316
from codegate.pipeline.secrets.manager import SecretsManager
1417
from codegate.providers.registry import ProviderRegistry
1518
from codegate.server import init_app
16-
from src.codegate.cli import UvicornServer
17-
from src.codegate.cli import cli
18-
from src.codegate.codegate_logging import LogLevel, LogFormat
19-
from uvicorn.config import Config as UvicornConfig
20-
from click.testing import CliRunner
21-
from pathlib import Path
19+
from src.codegate.cli import UvicornServer, cli
20+
from src.codegate.codegate_logging import LogFormat, LogLevel
2221

2322

2423
@pytest.fixture
@@ -176,12 +175,12 @@ def mock_app():
176175
@pytest.fixture
177176
def uvicorn_config(mock_app):
178177
# Assuming mock_app is defined to simulate ASGI application
179-
return UvicornConfig(app=mock_app, host='localhost', port=8000, log_level='info')
178+
return UvicornConfig(app=mock_app, host="localhost", port=8000, log_level="info")
180179

181180

182181
@pytest.fixture
183182
def server_instance(uvicorn_config):
184-
with patch('src.codegate.cli.Server', autospec=True) as mock_server_class:
183+
with patch("src.codegate.cli.Server", autospec=True) as mock_server_class:
185184
mock_server_instance = mock_server_class.return_value
186185
mock_server_instance.serve = AsyncMock()
187186
yield UvicornServer(uvicorn_config, mock_server_instance)
@@ -200,20 +199,22 @@ def cli_runner():
200199

201200
@pytest.fixture
202201
def mock_logging(mocker):
203-
return mocker.patch('your_cli_module.structlog.get_logger')
202+
return mocker.patch("your_cli_module.structlog.get_logger")
204203

205204

206205
@pytest.fixture
207206
def mock_setup_logging(mocker):
208-
return mocker.patch('your_cli_module.setup_logging')
207+
return mocker.patch("your_cli_module.setup_logging")
209208

210209

211210
def test_serve_default_options(cli_runner):
212211
"""Test serve command with default options."""
213212
# Use patches for run_servers and logging setup
214-
with patch("src.codegate.cli.run_servers") as mock_run, \
215-
patch("src.codegate.cli.structlog.get_logger") as mock_logging, \
216-
patch("src.codegate.cli.setup_logging") as mock_setup_logging:
213+
with (
214+
patch("src.codegate.cli.run_servers") as mock_run,
215+
patch("src.codegate.cli.structlog.get_logger") as mock_logging,
216+
patch("src.codegate.cli.setup_logging") as mock_setup_logging,
217+
):
217218

218219
logger_instance = MagicMock()
219220
mock_logging.return_value = logger_instance
@@ -236,9 +237,11 @@ def test_serve_default_options(cli_runner):
236237

237238
def test_serve_custom_options(cli_runner):
238239
"""Test serve command with custom options."""
239-
with patch("src.codegate.cli.run_servers") as mock_run, \
240-
patch("src.codegate.cli.structlog.get_logger") as mock_logging, \
241-
patch("src.codegate.cli.setup_logging") as mock_setup_logging:
240+
with (
241+
patch("src.codegate.cli.run_servers") as mock_run,
242+
patch("src.codegate.cli.structlog.get_logger") as mock_logging,
243+
patch("src.codegate.cli.setup_logging") as mock_setup_logging,
244+
):
242245

243246
logger_instance = MagicMock()
244247
mock_logging.return_value = logger_instance
@@ -248,15 +251,24 @@ def test_serve_custom_options(cli_runner):
248251
cli,
249252
[
250253
"serve",
251-
"--port", "8989",
252-
"--host", "localhost",
253-
"--log-level", "DEBUG",
254-
"--log-format", "TEXT",
255-
"--certs-dir", "./custom-certs",
256-
"--ca-cert", "custom-ca.crt",
257-
"--ca-key", "custom-ca.key",
258-
"--server-cert", "custom-server.crt",
259-
"--server-key", "custom-server.key",
254+
"--port",
255+
"8989",
256+
"--host",
257+
"localhost",
258+
"--log-level",
259+
"DEBUG",
260+
"--log-format",
261+
"TEXT",
262+
"--certs-dir",
263+
"./custom-certs",
264+
"--ca-cert",
265+
"custom-ca.crt",
266+
"--ca-key",
267+
"custom-ca.key",
268+
"--server-cert",
269+
"custom-server.crt",
270+
"--server-key",
271+
"custom-server.key",
260272
],
261273
)
262274

@@ -289,8 +301,9 @@ def test_serve_custom_options(cli_runner):
289301

290302
# Check if Config object attributes match the expected values
291303
for key, expected_value in expected_values.items():
292-
assert getattr(config_arg, key) == expected_value, \
293-
f"{key} does not match expected value"
304+
assert (
305+
getattr(config_arg, key) == expected_value
306+
), f"{key} does not match expected value"
294307

295308

296309
def test_serve_invalid_port(cli_runner):
@@ -310,21 +323,25 @@ def test_serve_invalid_log_level(cli_runner):
310323
@pytest.fixture
311324
def temp_config_file(tmp_path):
312325
config_path = tmp_path / "config.yaml"
313-
config_path.write_text("""
326+
config_path.write_text(
327+
"""
314328
log_level: DEBUG
315329
log_format: JSON
316330
port: 8989
317331
host: localhost
318332
certs_dir: ./test-certs
319-
""")
333+
"""
334+
)
320335
return config_path
321336

322337

323338
def test_serve_with_config_file(cli_runner, temp_config_file):
324339
"""Test serve command with config file."""
325-
with patch("src.codegate.cli.run_servers") as mock_run, \
326-
patch("src.codegate.cli.structlog.get_logger") as mock_logging, \
327-
patch("src.codegate.cli.setup_logging") as mock_setup_logging:
340+
with (
341+
patch("src.codegate.cli.run_servers") as mock_run,
342+
patch("src.codegate.cli.structlog.get_logger") as mock_logging,
343+
patch("src.codegate.cli.setup_logging") as mock_setup_logging,
344+
):
328345

329346
logger_instance = MagicMock()
330347
mock_logging.return_value = logger_instance
@@ -352,8 +369,9 @@ def test_serve_with_config_file(cli_runner, temp_config_file):
352369

353370
# Check if passed arguments match the expected values
354371
for key, expected_value in expected_values.items():
355-
assert getattr(config_arg, key) == expected_value, \
356-
f"{key} does not match expected value"
372+
assert (
373+
getattr(config_arg, key) == expected_value
374+
), f"{key} does not match expected value"
357375

358376

359377
def test_serve_with_nonexistent_config_file(cli_runner: CliRunner) -> None:
@@ -366,10 +384,12 @@ def test_serve_with_nonexistent_config_file(cli_runner: CliRunner) -> None:
366384
def test_serve_priority_resolution(cli_runner: CliRunner, temp_config_file: Path) -> None:
367385
"""Test serve command respects configuration priority."""
368386
# Set up environment variables and ensure they get cleaned up after the test
369-
with patch.dict(os.environ, {'LOG_LEVEL': 'INFO', 'PORT': '9999'}, clear=True), \
370-
patch('src.codegate.cli.run_servers') as mock_run, \
371-
patch('src.codegate.cli.structlog.get_logger') as mock_logging, \
372-
patch('src.codegate.cli.setup_logging') as mock_setup_logging:
387+
with (
388+
patch.dict(os.environ, {"LOG_LEVEL": "INFO", "PORT": "9999"}, clear=True),
389+
patch("src.codegate.cli.run_servers") as mock_run,
390+
patch("src.codegate.cli.structlog.get_logger") as mock_logging,
391+
patch("src.codegate.cli.setup_logging") as mock_setup_logging,
392+
):
373393
# Set up mock logger
374394
logger_instance = MagicMock()
375395
mock_logging.return_value = logger_instance
@@ -406,7 +426,7 @@ def test_serve_priority_resolution(cli_runner: CliRunner, temp_config_file: Path
406426
assert result.exit_code == 0
407427

408428
# Ensure logging setup was called with the highest priority settings (CLI arguments)
409-
mock_setup_logging.assert_called_once_with('ERROR', 'TEXT')
429+
mock_setup_logging.assert_called_once_with("ERROR", "TEXT")
410430
mock_logging.assert_called_with("codegate")
411431

412432
# Verify that the run_servers was called with the overridden settings
@@ -415,8 +435,8 @@ def test_serve_priority_resolution(cli_runner: CliRunner, temp_config_file: Path
415435
expected_values = {
416436
"port": 8080,
417437
"host": "example.com",
418-
"log_level": 'ERROR',
419-
"log_format": 'TEXT',
438+
"log_level": "ERROR",
439+
"log_format": "TEXT",
420440
"certs_dir": "./cli-certs",
421441
"ca_cert": "cli-ca.crt",
422442
"ca_key": "cli-ca.key",
@@ -426,15 +446,18 @@ def test_serve_priority_resolution(cli_runner: CliRunner, temp_config_file: Path
426446

427447
# Verify if Config object attributes match the expected values from CLI arguments
428448
for key, expected_value in expected_values.items():
429-
assert getattr(config_arg, key) == expected_value, \
430-
f"{key} does not match expected value"
449+
assert (
450+
getattr(config_arg, key) == expected_value
451+
), f"{key} does not match expected value"
431452

432453

433454
def test_serve_certificate_options(cli_runner: CliRunner) -> None:
434455
"""Test serve command with certificate options."""
435-
with patch('src.codegate.cli.run_servers') as mock_run, \
436-
patch('src.codegate.cli.structlog.get_logger') as mock_logging, \
437-
patch('src.codegate.cli.setup_logging') as mock_setup_logging:
456+
with (
457+
patch("src.codegate.cli.run_servers") as mock_run,
458+
patch("src.codegate.cli.structlog.get_logger") as mock_logging,
459+
patch("src.codegate.cli.setup_logging") as mock_setup_logging,
460+
):
438461
# Set up mock logger
439462
logger_instance = MagicMock()
440463
mock_logging.return_value = logger_instance
@@ -461,7 +484,7 @@ def test_serve_certificate_options(cli_runner: CliRunner) -> None:
461484
assert result.exit_code == 0
462485

463486
# Ensure logging setup was called with expected arguments
464-
mock_setup_logging.assert_called_once_with('INFO', 'JSON')
487+
mock_setup_logging.assert_called_once_with("INFO", "JSON")
465488
mock_logging.assert_called_with("codegate")
466489

467490
# Verify that run_servers was called with the provided certificate options
@@ -477,14 +500,16 @@ def test_serve_certificate_options(cli_runner: CliRunner) -> None:
477500

478501
# Check if Config object attributes match the expected values
479502
for key, expected_value in expected_values.items():
480-
assert getattr(config_arg, key) == expected_value, \
481-
f"{key} does not match expected value"
503+
assert (
504+
getattr(config_arg, key) == expected_value
505+
), f"{key} does not match expected value"
482506

483507

484508
def test_main_function() -> None:
485509
"""Test main function."""
486510
with patch("sys.argv", ["cli"]), patch("codegate.cli.cli") as mock_cli:
487511
from codegate.cli import main
512+
488513
main()
489514
mock_cli.assert_called_once()
490515

@@ -501,8 +526,10 @@ def mock_uvicorn_server():
501526

502527
@pytest.mark.asyncio
503528
async def test_uvicorn_server_cleanup(mock_uvicorn_server):
504-
with patch("asyncio.get_running_loop"), \
505-
patch.object(mock_uvicorn_server.server, 'shutdown', AsyncMock()):
529+
with (
530+
patch("asyncio.get_running_loop"),
531+
patch.object(mock_uvicorn_server.server, "shutdown", AsyncMock()),
532+
):
506533
# Mock the loop or other components as needed
507534

508535
# Start the server or trigger the condition you want to test

0 commit comments

Comments
 (0)