Skip to main content
Glama
test_settings.py14.3 kB
#!/usr/bin/env python3 """Unit tests for Settings configuration component. This test suite validates the Settings class and its configuration handling, including argument parsing, environment variable support, and base URL determination. """ import argparse import os from unittest.mock import Mock, patch import pytest from mcp_swagger.config.settings import Settings from mcp_swagger.models.swagger import SwaggerSpec # Local test copies of private functions to avoid import issues def _determine_base_url(args: argparse.Namespace, swagger_spec: dict) -> str: """Determine the base URL for the API.""" if args.base_url: return args.base_url # Try environment variable base_url = os.getenv("API_BASE_URL") if base_url: return base_url # Try to extract from spec if "schemes" in swagger_spec and "host" in swagger_spec: scheme = swagger_spec["schemes"][0] if swagger_spec["schemes"] else "http" return f"{scheme}://{swagger_spec['host']}" return "http://localhost:8000" def _get_api_token(args: argparse.Namespace) -> str | None: """Get API token from arguments or environment.""" return args.api_token or os.getenv("API_TOKEN") class TestSettings: """Test suite for Settings functionality.""" DEFAULT_TIMEOUT = 600.0 # Default timeout value in seconds def setup_method(self) -> None: """Set up test fixtures for each test method.""" self.sample_args = argparse.Namespace( swagger_spec="swagger.json", base_url=None, api_token=None, server_name="test-server", instructions=None, methods=["get", "post"], paths=["/api/*"], exclude_paths=["/internal/*"], tags=["public"], exclude_tags=["deprecated"], operation_ids=["getUser"], exclude_operation_ids=["deleteUser"], exclude_attributes=None, host="localhost", port=8080, transport="stdio", timeout=600.0, dry_run=False, ) self.sample_spec = SwaggerSpec.from_dict( { "swagger": "2.0", "host": "api.example.com", "schemes": ["https"], "basePath": "/v1", } ) def test_from_args_basic(self) -> None: """Test Settings creation from command-line arguments.""" # Arrange self.sample_args.base_url = "https://custom.api.com" self.sample_args.api_token = "secret123" # Act settings = Settings.from_args(self.sample_args, self.sample_spec) # Assert assert settings.swagger_spec_path == "swagger.json" assert settings.base_url == "https://custom.api.com" assert settings.api_token == "secret123" assert settings.server_name == "test-server" assert settings.methods == ["get", "post"] assert settings.paths == ["/api/*"] assert settings.exclude_paths == ["/internal/*"] assert settings.tags == ["public"] assert settings.exclude_tags == ["deprecated"] assert settings.operation_ids == ["getUser"] assert settings.exclude_operation_ids == ["deleteUser"] assert settings.host == "localhost" default_port = 8080 assert settings.port == default_port assert settings.transport == "stdio" assert settings.timeout == self.DEFAULT_TIMEOUT assert settings.dry_run is False def test_from_args_with_defaults(self) -> None: """Test Settings with default values.""" # Arrange minimal_args = argparse.Namespace( swagger_spec="spec.yaml", base_url=None, api_token=None, server_name="server", instructions=None, methods=None, paths=None, exclude_paths=None, tags=None, exclude_tags=None, operation_ids=None, exclude_operation_ids=None, exclude_attributes=None, host="127.0.0.1", # Use localhost instead of all interfaces port=3000, transport="tcp", timeout=600.0, dry_run=True, ) # Act swagger_spec = SwaggerSpec.from_dict({}) with patch.dict(os.environ, {}, clear=True): settings = Settings.from_args(minimal_args, swagger_spec) # Assert assert settings.swagger_spec_path == "spec.yaml" assert settings.base_url == "http://localhost:8000" # Default assert settings.api_token is None assert settings.methods is None assert settings.paths is None assert settings.dry_run is True def test_determine_base_url_from_args(self) -> None: """Test base URL determination from arguments.""" # Arrange args = Mock() args.base_url = "https://args.api.com" spec = {} # Act base_url = _determine_base_url(args, spec) # Assert assert base_url == "https://args.api.com" def test_determine_base_url_from_env(self) -> None: """Test base URL determination from environment variable.""" # Arrange args = Mock() args.base_url = None spec = {} # Act with patch.dict(os.environ, {"API_BASE_URL": "https://env.api.com"}): base_url = _determine_base_url(args, spec) # Assert assert base_url == "https://env.api.com" def test_determine_base_url_from_spec(self) -> None: """Test base URL determination from Swagger specification.""" # Arrange args = Mock() args.base_url = None spec = {"schemes": ["https", "http"], "host": "spec.api.com"} # Act with patch.dict(os.environ, {}, clear=True): base_url = _determine_base_url(args, spec) # Assert assert base_url == "https://spec.api.com" # Uses first scheme def test_determine_base_url_from_spec_http(self) -> None: """Test base URL with HTTP scheme from spec.""" # Arrange args = Mock() args.base_url = None spec = {"schemes": ["http"], "host": "api.local"} # Act with patch.dict(os.environ, {}, clear=True): base_url = _determine_base_url(args, spec) # Assert assert base_url == "http://api.local" def test_determine_base_url_default(self) -> None: """Test default base URL when no source is available.""" # Arrange args = Mock() args.base_url = None spec = {} # Act with patch.dict(os.environ, {}, clear=True): base_url = _determine_base_url(args, spec) # Assert assert base_url == "http://localhost:8000" def test_determine_base_url_priority(self) -> None: """Test priority order for base URL determination.""" # Arrange args = Mock() args.base_url = "https://args.api.com" spec = {"schemes": ["https"], "host": "spec.api.com"} # Act - Args takes priority over env and spec with patch.dict(os.environ, {"API_BASE_URL": "https://env.api.com"}): base_url = _determine_base_url(args, spec) # Assert assert base_url == "https://args.api.com" # Act - Env takes priority over spec when no args args.base_url = None with patch.dict(os.environ, {"API_BASE_URL": "https://env.api.com"}): base_url = _determine_base_url(args, spec) # Assert assert base_url == "https://env.api.com" def test_get_api_token_from_args(self) -> None: """Test API token retrieval from arguments.""" # Arrange args = Mock() args.api_token = "token_from_args" # Act token = _get_api_token(args) # Assert assert token == "token_from_args" def test_get_api_token_from_env(self) -> None: """Test API token retrieval from environment variable.""" # Arrange args = Mock() args.api_token = None # Act with patch.dict(os.environ, {"API_TOKEN": "token_from_env"}): token = _get_api_token(args) # Assert assert token == "token_from_env" def test_get_api_token_none(self) -> None: """Test API token when not provided.""" # Arrange args = Mock() args.api_token = None # Act with patch.dict(os.environ, {}, clear=True): token = _get_api_token(args) # Assert assert token is None def test_get_api_token_priority(self) -> None: """Test priority for API token sources.""" # Arrange args = Mock() args.api_token = "args_token" # Act - Args takes priority over env with patch.dict(os.environ, {"API_TOKEN": "env_token"}): token = _get_api_token(args) # Assert assert token == "args_token" def test_spec_with_empty_schemes(self) -> None: """Test base URL determination with empty schemes list.""" # Arrange args = Mock() args.base_url = None spec = {"schemes": [], "host": "api.example.com"} # Act with patch.dict(os.environ, {}, clear=True): base_url = _determine_base_url(args, spec) # Assert assert base_url == "http://api.example.com" # Defaults to http def test_spec_missing_host(self) -> None: """Test base URL determination when spec has schemes but no host.""" # Arrange args = Mock() args.base_url = None spec = {"schemes": ["https"]} # No host field # Act with patch.dict(os.environ, {}, clear=True): base_url = _determine_base_url(args, spec) # Assert assert base_url == "http://localhost:8000" # Falls back to default def test_settings_dataclass_fields(self) -> None: """Test that Settings dataclass has all expected fields.""" # Arrange & Act settings = Settings( swagger_spec_path="test.json", base_url="https://api.test.com", api_token="token123", server_name="test", instructions=None, methods=["get"], paths=["/api/*"], exclude_paths=["/admin/*"], tags=["v1"], exclude_tags=["beta"], operation_ids=["op1"], exclude_operation_ids=["op2"], exclude_attributes=["user.email"], host="127.0.0.1", port=9000, transport="tcp", timeout=600.0, dry_run=True, ) # Assert - All fields are accessible assert settings.swagger_spec_path == "test.json" assert settings.base_url == "https://api.test.com" assert settings.api_token == "token123" assert settings.server_name == "test" assert settings.methods == ["get"] assert settings.paths == ["/api/*"] assert settings.exclude_paths == ["/admin/*"] assert settings.tags == ["v1"] assert settings.exclude_tags == ["beta"] assert settings.operation_ids == ["op1"] assert settings.exclude_operation_ids == ["op2"] assert settings.host == "127.0.0.1" test_port = 9000 assert settings.port == test_port assert settings.transport == "tcp" assert settings.timeout == self.DEFAULT_TIMEOUT assert settings.dry_run is True def test_from_args_preserves_list_types(self) -> None: """Test that list arguments are properly preserved.""" # Arrange args = argparse.Namespace( swagger_spec="spec.json", base_url="https://api.com", api_token=None, server_name="server", instructions=None, methods=["get", "post", "put"], paths=["/users/*", "/posts/*"], exclude_paths=["/admin/*", "/internal/*"], tags=["public", "v1", "stable"], exclude_tags=["deprecated", "beta"], operation_ids=["op1", "op2", "op3"], exclude_operation_ids=["deleteAll", "purge"], exclude_attributes=["password", "secret"], host="localhost", port=8080, transport="stdio", timeout=600.0, dry_run=False, ) # Act swagger_spec = SwaggerSpec.from_dict({}) settings = Settings.from_args(args, swagger_spec) # Assert - Lists are preserved correctly assert settings.methods == ["get", "post", "put"] expected_method_count = 3 assert len(settings.methods) == expected_method_count assert settings.paths == ["/users/*", "/posts/*"] expected_path_count = 2 assert len(settings.paths) == expected_path_count assert settings.tags == ["public", "v1", "stable"] expected_tag_count = 3 assert len(settings.tags) == expected_tag_count def test_from_args_with_instructions(self) -> None: """Test Settings creation with instructions argument.""" # Arrange self.sample_args.instructions = "You are a helpful API assistant" # Act settings = Settings.from_args(self.sample_args, self.sample_spec) # Assert assert settings.instructions == "You are a helpful API assistant" assert settings.server_name == "test-server" if __name__ == "__main__": # Run tests with pytest if available, otherwise run basic tests try: pytest.main([__file__, "-v"]) except ImportError: print("pytest not installed, running basic tests...") test_suite = TestSettings() test_methods = [m for m in dir(test_suite) if m.startswith("test_")] for method_name in test_methods: test_suite.setup_method() method = getattr(test_suite, method_name) try: method() print(f"✓ {method_name}") except AssertionError as e: print(f"✗ {method_name}: {e}") print("\nBasic tests completed!")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zecure/mcp_swagger'

If you have feedback or need assistance with the MCP directory API, please join our Discord server