API / kiro-gateway /tests /unit /test_main_cli.py
sshinmen's picture
Clean deploy to HF Space
bf9e111
Raw
History Blame Contribute Delete
15.9 kB
# -*- coding: utf-8 -*-
"""
Unit tests for main.py CLI functions.
Tests for parse_cli_args(), resolve_server_config(), and print_startup_banner().
"""
import pytest
import argparse
import sys
from unittest.mock import patch, MagicMock
from io import StringIO
class TestParseCliArgs:
"""Tests for parse_cli_args() function."""
def test_default_values_are_none(self):
"""
What it does: Verifies that default values for host and port are None.
Purpose: Ensure that None indicates "use env or default" in priority resolution.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with no arguments...")
with patch.object(sys, 'argv', ['main.py']):
args = parse_cli_args()
print(f"args.host: {args.host}")
print(f"args.port: {args.port}")
print(f"Comparing: Expected host=None, port=None")
assert args.host is None
assert args.port is None
def test_port_argument_long_form(self):
"""
What it does: Verifies that --port argument is parsed correctly.
Purpose: Ensure long form --port works.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --port 9000...")
with patch.object(sys, 'argv', ['main.py', '--port', '9000']):
args = parse_cli_args()
print(f"args.port: {args.port}")
print(f"Comparing: Expected 9000, Got {args.port}")
assert args.port == 9000
def test_port_argument_short_form(self):
"""
What it does: Verifies that -p argument is parsed correctly.
Purpose: Ensure short form -p works.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with -p 8080...")
with patch.object(sys, 'argv', ['main.py', '-p', '8080']):
args = parse_cli_args()
print(f"args.port: {args.port}")
print(f"Comparing: Expected 8080, Got {args.port}")
assert args.port == 8080
def test_host_argument_long_form(self):
"""
What it does: Verifies that --host argument is parsed correctly.
Purpose: Ensure long form --host works.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --host 127.0.0.1...")
with patch.object(sys, 'argv', ['main.py', '--host', '127.0.0.1']):
args = parse_cli_args()
print(f"args.host: {args.host}")
print(f"Comparing: Expected '127.0.0.1', Got '{args.host}'")
assert args.host == "127.0.0.1"
def test_host_argument_short_form(self):
"""
What it does: Verifies that -H argument is parsed correctly.
Purpose: Ensure short form -H works.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with -H 192.168.1.1...")
with patch.object(sys, 'argv', ['main.py', '-H', '192.168.1.1']):
args = parse_cli_args()
print(f"args.host: {args.host}")
print(f"Comparing: Expected '192.168.1.1', Got '{args.host}'")
assert args.host == "192.168.1.1"
def test_both_arguments_together(self):
"""
What it does: Verifies that both --host and --port can be used together.
Purpose: Ensure both arguments work simultaneously.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --host 0.0.0.0 --port 3000...")
with patch.object(sys, 'argv', ['main.py', '--host', '0.0.0.0', '--port', '3000']):
args = parse_cli_args()
print(f"args.host: {args.host}")
print(f"args.port: {args.port}")
assert args.host == "0.0.0.0"
assert args.port == 3000
def test_short_forms_together(self):
"""
What it does: Verifies that both -H and -p can be used together.
Purpose: Ensure short forms work simultaneously.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with -H 127.0.0.1 -p 5000...")
with patch.object(sys, 'argv', ['main.py', '-H', '127.0.0.1', '-p', '5000']):
args = parse_cli_args()
print(f"args.host: {args.host}")
print(f"args.port: {args.port}")
assert args.host == "127.0.0.1"
assert args.port == 5000
class TestResolveServerConfig:
"""Tests for resolve_server_config() function - priority hierarchy."""
def test_cli_args_take_priority_over_env(self):
"""
What it does: Verifies that CLI arguments have highest priority.
Purpose: Ensure CLI args override environment variables.
"""
print("Setup: Importing resolve_server_config...")
from main import resolve_server_config
print("Setup: Creating args with host=127.0.0.1, port=9000...")
args = argparse.Namespace(host="127.0.0.1", port=9000)
print("Action: Calling resolve_server_config with CLI args...")
# Even if env vars are set, CLI should win
with patch('main.SERVER_HOST', '0.0.0.0'), \
patch('main.SERVER_PORT', 8000), \
patch('main.DEFAULT_SERVER_HOST', '0.0.0.0'), \
patch('main.DEFAULT_SERVER_PORT', 8000):
host, port = resolve_server_config(args)
print(f"Resolved host: {host}")
print(f"Resolved port: {port}")
print(f"Comparing: Expected ('127.0.0.1', 9000)")
assert host == "127.0.0.1"
assert port == 9000
def test_env_vars_take_priority_over_defaults(self):
"""
What it does: Verifies that env vars have priority over defaults.
Purpose: Ensure env vars are used when CLI args are not provided.
"""
print("Setup: Importing resolve_server_config...")
from main import resolve_server_config
print("Setup: Creating args with host=None, port=None (no CLI args)...")
args = argparse.Namespace(host=None, port=None)
print("Action: Calling resolve_server_config with env vars set...")
# SERVER_HOST and SERVER_PORT are different from defaults
with patch('main.SERVER_HOST', '192.168.1.100'), \
patch('main.SERVER_PORT', 3000), \
patch('main.DEFAULT_SERVER_HOST', '0.0.0.0'), \
patch('main.DEFAULT_SERVER_PORT', 8000):
host, port = resolve_server_config(args)
print(f"Resolved host: {host}")
print(f"Resolved port: {port}")
print(f"Comparing: Expected ('192.168.1.100', 3000)")
assert host == "192.168.1.100"
assert port == 3000
def test_defaults_used_when_nothing_set(self):
"""
What it does: Verifies that defaults are used when nothing else is set.
Purpose: Ensure default values work correctly.
"""
print("Setup: Importing resolve_server_config...")
from main import resolve_server_config
print("Setup: Creating args with host=None, port=None...")
args = argparse.Namespace(host=None, port=None)
print("Action: Calling resolve_server_config with defaults...")
# SERVER_HOST and SERVER_PORT equal to defaults (no env override)
with patch('main.SERVER_HOST', '0.0.0.0'), \
patch('main.SERVER_PORT', 8000), \
patch('main.DEFAULT_SERVER_HOST', '0.0.0.0'), \
patch('main.DEFAULT_SERVER_PORT', 8000):
host, port = resolve_server_config(args)
print(f"Resolved host: {host}")
print(f"Resolved port: {port}")
print(f"Comparing: Expected ('0.0.0.0', 8000)")
assert host == "0.0.0.0"
assert port == 8000
def test_cli_host_only_env_port(self):
"""
What it does: Verifies mixed priority - CLI host with env port.
Purpose: Ensure each argument is resolved independently.
"""
print("Setup: Importing resolve_server_config...")
from main import resolve_server_config
print("Setup: Creating args with host='127.0.0.1', port=None...")
args = argparse.Namespace(host="127.0.0.1", port=None)
print("Action: Calling resolve_server_config...")
with patch('main.SERVER_HOST', '0.0.0.0'), \
patch('main.SERVER_PORT', 9000), \
patch('main.DEFAULT_SERVER_HOST', '0.0.0.0'), \
patch('main.DEFAULT_SERVER_PORT', 8000):
host, port = resolve_server_config(args)
print(f"Resolved host: {host}")
print(f"Resolved port: {port}")
print(f"Comparing: Expected ('127.0.0.1', 9000)")
assert host == "127.0.0.1" # From CLI
assert port == 9000 # From env (different from default)
def test_cli_port_only_env_host(self):
"""
What it does: Verifies mixed priority - CLI port with env host.
Purpose: Ensure each argument is resolved independently.
"""
print("Setup: Importing resolve_server_config...")
from main import resolve_server_config
print("Setup: Creating args with host=None, port=5000...")
args = argparse.Namespace(host=None, port=5000)
print("Action: Calling resolve_server_config...")
with patch('main.SERVER_HOST', '192.168.1.1'), \
patch('main.SERVER_PORT', 8000), \
patch('main.DEFAULT_SERVER_HOST', '0.0.0.0'), \
patch('main.DEFAULT_SERVER_PORT', 8000):
host, port = resolve_server_config(args)
print(f"Resolved host: {host}")
print(f"Resolved port: {port}")
print(f"Comparing: Expected ('192.168.1.1', 5000)")
assert host == "192.168.1.1" # From env (different from default)
assert port == 5000 # From CLI
class TestPrintStartupBanner:
"""Tests for print_startup_banner() function."""
def test_banner_contains_url(self, capsys):
"""
What it does: Verifies that banner contains the server URL.
Purpose: Ensure URL is displayed to user.
"""
print("Setup: Importing print_startup_banner...")
from main import print_startup_banner
print("Action: Calling print_startup_banner('0.0.0.0', 8000)...")
print_startup_banner("0.0.0.0", 8000)
captured = capsys.readouterr()
print(f"Captured output length: {len(captured.out)}")
# When host is 0.0.0.0, display should show localhost
assert "localhost:8000" in captured.out or "8000" in captured.out
def test_banner_contains_custom_port(self, capsys):
"""
What it does: Verifies that banner shows custom port.
Purpose: Ensure custom port is displayed correctly.
"""
print("Setup: Importing print_startup_banner...")
from main import print_startup_banner
print("Action: Calling print_startup_banner('127.0.0.1', 9000)...")
print_startup_banner("127.0.0.1", 9000)
captured = capsys.readouterr()
print(f"Captured output contains '9000': {'9000' in captured.out}")
assert "9000" in captured.out
def test_banner_contains_docs_url(self, capsys):
"""
What it does: Verifies that banner contains API docs URL.
Purpose: Ensure /docs endpoint is mentioned.
"""
print("Setup: Importing print_startup_banner...")
from main import print_startup_banner
print("Action: Calling print_startup_banner('0.0.0.0', 8000)...")
print_startup_banner("0.0.0.0", 8000)
captured = capsys.readouterr()
print(f"Captured output contains '/docs': {'/docs' in captured.out}")
assert "/docs" in captured.out
def test_banner_contains_health_url(self, capsys):
"""
What it does: Verifies that banner contains health check URL.
Purpose: Ensure /health endpoint is mentioned.
"""
print("Setup: Importing print_startup_banner...")
from main import print_startup_banner
print("Action: Calling print_startup_banner('0.0.0.0', 8000)...")
print_startup_banner("0.0.0.0", 8000)
captured = capsys.readouterr()
print(f"Captured output contains '/health': {'/health' in captured.out}")
assert "/health" in captured.out
class TestCliHelp:
"""Tests for CLI help output."""
def test_help_shows_port_option(self):
"""
What it does: Verifies that --help shows port option.
Purpose: Ensure help is informative.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --help...")
with patch.object(sys, 'argv', ['main.py', '--help']):
with pytest.raises(SystemExit) as exc_info:
parse_cli_args()
print(f"Exit code: {exc_info.value.code}")
# --help exits with code 0
assert exc_info.value.code == 0
def test_help_shows_host_option(self, capsys):
"""
What it does: Verifies that --help output contains host option.
Purpose: Ensure host option is documented.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --help...")
with patch.object(sys, 'argv', ['main.py', '--help']):
with pytest.raises(SystemExit):
parse_cli_args()
captured = capsys.readouterr()
print(f"Help output contains '--host': {'--host' in captured.out}")
print(f"Help output contains '-H': {'-H' in captured.out}")
assert "--host" in captured.out
assert "-H" in captured.out
class TestCliVersion:
"""Tests for CLI version output."""
def test_version_flag_exits_with_zero(self):
"""
What it does: Verifies that --version exits with code 0.
Purpose: Ensure version flag works correctly.
"""
print("Setup: Importing parse_cli_args...")
from main import parse_cli_args
print("Action: Calling parse_cli_args with --version...")
with patch.object(sys, 'argv', ['main.py', '--version']):
with pytest.raises(SystemExit) as exc_info:
parse_cli_args()
print(f"Exit code: {exc_info.value.code}")
assert exc_info.value.code == 0
def test_version_shows_app_version(self, capsys):
"""
What it does: Verifies that --version shows application version.
Purpose: Ensure version is displayed.
"""
print("Setup: Importing parse_cli_args and APP_VERSION...")
from main import parse_cli_args
from kiro.config import APP_VERSION
print("Action: Calling parse_cli_args with --version...")
with patch.object(sys, 'argv', ['main.py', '--version']):
with pytest.raises(SystemExit):
parse_cli_args()
captured = capsys.readouterr()
print(f"Version output: {captured.out}")
print(f"APP_VERSION: {APP_VERSION}")
assert APP_VERSION in captured.out