1
1
"""Tests for the server module."""
2
2
3
+ import os
3
4
from unittest .mock import MagicMock , patch , AsyncMock
4
5
5
6
import pytest
16
17
from src .codegate .codegate_logging import LogLevel , LogFormat
17
18
from uvicorn .config import Config as UvicornConfig
18
19
from click .testing import CliRunner
20
+ from pathlib import Path
19
21
20
22
21
23
@pytest .fixture
@@ -277,7 +279,8 @@ def test_serve_custom_options(cli_runner):
277
279
278
280
# Check if Config object attributes match the expected values
279
281
for key , expected_value in expected_values .items ():
280
- assert getattr (config_arg , key ) == expected_value , f"{ key } does not match expected value"
282
+ assert getattr (config_arg , key ) == expected_value , \
283
+ f"{ key } does not match expected value"
281
284
282
285
283
286
def test_serve_invalid_port (cli_runner ):
@@ -326,7 +329,7 @@ def test_serve_with_config_file(cli_runner, temp_config_file):
326
329
327
330
# Validate that run_servers was called with the expected configuration
328
331
mock_run .assert_called_once ()
329
- config_arg = mock_run .call_args [0 ][0 ] # Assuming Config object is the first positional argument
332
+ config_arg = mock_run .call_args [0 ][0 ]
330
333
331
334
# Define expected values based on the temp_config_file content
332
335
expected_values = {
@@ -338,6 +341,160 @@ def test_serve_with_config_file(cli_runner, temp_config_file):
338
341
}
339
342
340
343
# Check if passed arguments match the expected values
344
+ for key , expected_value in expected_values .items ():
345
+ assert getattr (config_arg , key ) == expected_value , \
346
+ f"{ key } does not match expected value"
347
+
348
+
349
+ def test_serve_with_nonexistent_config_file (cli_runner : CliRunner ) -> None :
350
+ """Test serve command with nonexistent config file."""
351
+ result = cli_runner .invoke (cli , ["serve" , "--config" , "nonexistent.yaml" ])
352
+ assert result .exit_code == 2
353
+ assert "does not exist" in result .output
354
+
355
+
356
+ def test_serve_priority_resolution (cli_runner : CliRunner , temp_config_file : Path ) -> None :
357
+ """Test serve command respects configuration priority."""
358
+ # Set up environment variables and ensure they get cleaned up after the test
359
+ with patch .dict (os .environ , {'LOG_LEVEL' : 'INFO' , 'PORT' : '9999' }, clear = True ), \
360
+ patch ('src.codegate.cli.run_servers' ) as mock_run , \
361
+ patch ('src.codegate.cli.structlog.get_logger' ) as mock_logging , \
362
+ patch ('src.codegate.cli.setup_logging' ) as mock_setup_logging :
363
+ # Set up mock logger
364
+ logger_instance = MagicMock ()
365
+ mock_logging .return_value = logger_instance
366
+
367
+ # Execute CLI command with specific options overriding environment and config file settings
368
+ result = cli_runner .invoke (
369
+ cli ,
370
+ [
371
+ "serve" ,
372
+ "--config" ,
373
+ str (temp_config_file ),
374
+ "--port" ,
375
+ "8080" ,
376
+ "--host" ,
377
+ "example.com" ,
378
+ "--log-level" ,
379
+ "ERROR" ,
380
+ "--log-format" ,
381
+ "TEXT" ,
382
+ "--certs-dir" ,
383
+ "./cli-certs" ,
384
+ "--ca-cert" ,
385
+ "cli-ca.crt" ,
386
+ "--ca-key" ,
387
+ "cli-ca.key" ,
388
+ "--server-cert" ,
389
+ "cli-server.crt" ,
390
+ "--server-key" ,
391
+ "cli-server.key" ,
392
+ ],
393
+ )
394
+
395
+ # Check the result of the command
396
+ assert result .exit_code == 0
397
+
398
+ # Ensure logging setup was called with the highest priority settings (CLI arguments)
399
+ mock_setup_logging .assert_called_once_with ('ERROR' , 'TEXT' )
400
+ mock_logging .assert_called_with ("codegate" )
401
+
402
+ # Verify that the run_servers was called with the overridden settings
403
+ config_arg = mock_run .call_args [0 ][0 ] # Assuming Config is the first positional arg
404
+
405
+ expected_values = {
406
+ "port" : 8080 ,
407
+ "host" : "example.com" ,
408
+ "log_level" : 'ERROR' ,
409
+ "log_format" : 'TEXT' ,
410
+ "certs_dir" : "./cli-certs" ,
411
+ "ca_cert" : "cli-ca.crt" ,
412
+ "ca_key" : "cli-ca.key" ,
413
+ "server_cert" : "cli-server.crt" ,
414
+ "server_key" : "cli-server.key" ,
415
+ }
416
+
417
+ # Verify if Config object attributes match the expected values from CLI arguments
341
418
for key , expected_value in expected_values .items ():
342
419
assert getattr (config_arg , key ) == expected_value , f"{ key } does not match expected value"
343
420
421
+
422
+ def test_serve_certificate_options (cli_runner : CliRunner ) -> None :
423
+ """Test serve command with certificate options."""
424
+ with patch ('src.codegate.cli.run_servers' ) as mock_run , \
425
+ patch ('src.codegate.cli.structlog.get_logger' ) as mock_logging , \
426
+ patch ('src.codegate.cli.setup_logging' ) as mock_setup_logging :
427
+ # Set up mock logger
428
+ logger_instance = MagicMock ()
429
+ mock_logging .return_value = logger_instance
430
+
431
+ # Execute CLI command with certificate options
432
+ result = cli_runner .invoke (
433
+ cli ,
434
+ [
435
+ "serve" ,
436
+ "--certs-dir" ,
437
+ "./custom-certs" ,
438
+ "--ca-cert" ,
439
+ "custom-ca.crt" ,
440
+ "--ca-key" ,
441
+ "custom-ca.key" ,
442
+ "--server-cert" ,
443
+ "custom-server.crt" ,
444
+ "--server-key" ,
445
+ "custom-server.key" ,
446
+ ],
447
+ )
448
+
449
+ # Check the result of the command
450
+ assert result .exit_code == 0
451
+
452
+ # Ensure logging setup was called with expected arguments
453
+ mock_setup_logging .assert_called_once_with ('INFO' , 'JSON' )
454
+ mock_logging .assert_called_with ("codegate" )
455
+
456
+ # Verify that run_servers was called with the provided certificate options
457
+ config_arg = mock_run .call_args [0 ][0 ] # Assuming Config is the first positional arg
458
+
459
+ expected_values = {
460
+ "certs_dir" : "./custom-certs" ,
461
+ "ca_cert" : "custom-ca.crt" ,
462
+ "ca_key" : "custom-ca.key" ,
463
+ "server_cert" : "custom-server.crt" ,
464
+ "server_key" : "custom-server.key" ,
465
+ }
466
+
467
+ # Check if Config object attributes match the expected values
468
+ for key , expected_value in expected_values .items ():
469
+ assert getattr (config_arg , key ) == expected_value , f"{ key } does not match expected value"
470
+
471
+
472
+ def test_main_function () -> None :
473
+ """Test main function."""
474
+ with patch ("sys.argv" , ["cli" ]), patch ("codegate.cli.cli" ) as mock_cli :
475
+ from codegate .cli import main
476
+ main ()
477
+ mock_cli .assert_called_once ()
478
+
479
+
480
+ @pytest .fixture
481
+ def mock_uvicorn_server ():
482
+ mock_config = MagicMock () # Setup the configuration mock
483
+ mock_server = MagicMock (spec = UvicornServer )
484
+ mock_server .shutdown = AsyncMock () # Ensure shutdown is an async mock
485
+
486
+ uvicorn_server = UvicornServer (config = mock_config , server = mock_server )
487
+ return uvicorn_server
488
+
489
+
490
+ @pytest .mark .asyncio
491
+ async def test_uvicorn_server_cleanup (mock_uvicorn_server ):
492
+ with patch ("asyncio.get_running_loop" ), \
493
+ patch .object (mock_uvicorn_server .server , 'shutdown' , AsyncMock ()):
494
+ # Mock the loop or other components as needed
495
+
496
+ # Start the server or trigger the condition you want to test
497
+ await mock_uvicorn_server .cleanup () # This should now complete without error
498
+
499
+ # Verify that the shutdown was called
500
+ mock_uvicorn_server .server .shutdown .assert_awaited_once ()
0 commit comments