Skip to main content
Glama
mfang0126

API Aggregator MCP Server

by mfang0126
test_main.py15.4 kB
"""Tests for main application module.""" import os import pytest from unittest.mock import patch, Mock, MagicMock import uvicorn from src.main import create_app, main from src.server import MCPServer class TestCreateApp: """Test cases for create_app function.""" @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_no_api_keys(self, mock_get_settings, mock_validate_api_keys): """Test app creation when no API keys are available.""" # Mock settings mock_settings = Mock() mock_get_settings.return_value = mock_settings # Mock API key validation - no keys available mock_validate_api_keys.return_value = { "weather": False, "news": False, "stock": False, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server app = create_app() # Verify server was created with settings mock_server_class.assert_called_once_with(mock_settings) # Verify no tools were registered (no API keys available) assert mock_server.register_tool.call_count == 0 assert app == mock_server @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_all_api_keys_available(self, mock_get_settings, mock_validate_api_keys): """Test app creation when all API keys are available.""" mock_settings = Mock() mock_get_settings.return_value = mock_settings # Mock API key validation - all keys available mock_validate_api_keys.return_value = { "weather": True, "news": True, "stock": True, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server app = create_app() # Verify server was created mock_server_class.assert_called_once_with(mock_settings) # Verify all tools were registered (4 total: 1 weather, 1 news, 2 stock) assert mock_server.register_tool.call_count == 4 # Verify specific tools were registered by checking call arguments tool_names = [call[1]["name"] for call in mock_server.register_tool.call_args_list] expected_tools = {"get_weather", "get_news", "get_stock_price", "search_stocks"} assert expected_tools.issubset(set(tool_names)) @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_partial_api_keys(self, mock_get_settings, mock_validate_api_keys): """Test app creation when only some API keys are available.""" mock_settings = Mock() mock_get_settings.return_value = mock_settings # Mock API key validation - only weather and stock available mock_validate_api_keys.return_value = { "weather": True, "news": False, # Missing news API key "stock": True, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server app = create_app() # Should register weather + 2 stock tools = 3 total assert mock_server.register_tool.call_count == 3 # Verify specific tools were registered tool_names = [call[1]["name"] for call in mock_server.register_tool.call_args_list] assert "get_weather" in tool_names assert "get_stock_price" in tool_names assert "search_stocks" in tool_names assert "get_news" not in tool_names # Should not be registered @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_weather_tool_registration(self, mock_get_settings, mock_validate_api_keys): """Test weather tool registration details.""" mock_settings = Mock() mock_get_settings.return_value = mock_settings mock_validate_api_keys.return_value = { "weather": True, "news": False, "stock": False, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server create_app() # Verify weather tool was registered with correct parameters mock_server.register_tool.assert_called_once() call_args = mock_server.register_tool.call_args assert call_args[1]["name"] == "get_weather" assert "weather information" in call_args[1]["description"].lower() assert "input_schema" in call_args[1] assert "handler" in call_args[1] @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_news_tool_registration(self, mock_get_settings, mock_validate_api_keys): """Test news tool registration details.""" mock_settings = Mock() mock_get_settings.return_value = mock_settings mock_validate_api_keys.return_value = { "weather": False, "news": True, "stock": False, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server create_app() # Verify news tool was registered mock_server.register_tool.assert_called_once() call_args = mock_server.register_tool.call_args assert call_args[1]["name"] == "get_news" assert "news" in call_args[1]["description"].lower() @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_stock_tools_registration(self, mock_get_settings, mock_validate_api_keys): """Test stock tools registration details.""" mock_settings = Mock() mock_get_settings.return_value = mock_settings mock_validate_api_keys.return_value = { "weather": False, "news": False, "stock": True, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {} mock_server_class.return_value = mock_server create_app() # Should register 2 stock tools assert mock_server.register_tool.call_count == 2 # Get all tool names tool_names = [call[1]["name"] for call in mock_server.register_tool.call_args_list] assert "get_stock_price" in tool_names assert "search_stocks" in tool_names @patch("src.main.validate_api_keys") @patch("src.main.get_settings") def test_create_app_debug_logging(self, mock_get_settings, mock_validate_api_keys): """Test that debug information is logged correctly.""" mock_settings = Mock() mock_settings.debug = True mock_get_settings.return_value = mock_settings mock_validate_api_keys.return_value = { "weather": True, "news": False, "stock": False, } with patch("src.main.MCPServer") as mock_server_class: mock_server = Mock(spec=MCPServer) mock_server._tools = {"get_weather": Mock()} mock_server_class.return_value = mock_server with patch("src.main.logger") as mock_logger: create_app() # Verify initialization log was called mock_logger.info.assert_called() # Check that the final log call includes tool information final_log_call = mock_logger.info.call_args_list[-1] log_message = final_log_call[0][0] assert "MCP Server initialized" in log_message class TestMain: """Test cases for main function.""" @patch("src.main.uvicorn.run") @patch("src.main.create_app") @patch("src.main.get_settings") def test_main_function_calls(self, mock_get_settings, mock_create_app, mock_uvicorn_run): """Test that main function calls all necessary components.""" # Mock settings mock_settings = Mock() mock_settings.host = "localhost" mock_settings.port = 8000 mock_settings.debug = False mock_settings.log_level = "INFO" mock_get_settings.return_value = mock_settings # Mock MCP server mock_server = Mock() mock_app = Mock() mock_server.get_app.return_value = mock_app mock_create_app.return_value = mock_server main() # Verify create_app was called mock_create_app.assert_called_once() # Verify uvicorn.run was called with correct parameters mock_uvicorn_run.assert_called_once_with( mock_app, host="localhost", port=8000, log_level="info", reload=False, ) @patch("src.main.uvicorn.run") @patch("src.main.create_app") @patch("src.main.get_settings") def test_main_with_debug_settings(self, mock_get_settings, mock_create_app, mock_uvicorn_run): """Test main function with debug settings enabled.""" mock_settings = Mock() mock_settings.host = "0.0.0.0" mock_settings.port = 9000 mock_settings.debug = True mock_settings.log_level = "DEBUG" mock_get_settings.return_value = mock_settings mock_server = Mock() mock_app = Mock() mock_server.get_app.return_value = mock_app mock_create_app.return_value = mock_server main() # Verify uvicorn.run was called with debug settings mock_uvicorn_run.assert_called_once_with( mock_app, host="0.0.0.0", port=9000, log_level="debug", reload=True, # Should be True when debug=True ) @patch("src.main.uvicorn.run") @patch("src.main.create_app") @patch("src.main.get_settings") @patch("logging.basicConfig") def test_main_logging_configuration(self, mock_logging_config, mock_get_settings, mock_create_app, mock_uvicorn_run): """Test that logging is configured correctly.""" mock_settings = Mock() mock_settings.host = "localhost" mock_settings.port = 8000 mock_settings.debug = False mock_settings.log_level = "WARNING" mock_get_settings.return_value = mock_settings mock_server = Mock() mock_app = Mock() mock_server.get_app.return_value = mock_app mock_create_app.return_value = mock_server with patch("logging.WARNING", 30): # Mock logging level constant main() # Verify logging was configured with correct level mock_logging_config.assert_called_once() call_args = mock_logging_config.call_args # The level should be the result of getattr(logging, "WARNING") assert "level" in call_args[1] @patch("src.main.uvicorn.run") @patch("src.main.create_app") @patch("src.main.get_settings") def test_main_server_startup_logging(self, mock_get_settings, mock_create_app, mock_uvicorn_run): """Test that server startup is logged correctly.""" mock_settings = Mock() mock_settings.host = "localhost" mock_settings.port = 8000 mock_settings.debug = False mock_settings.log_level = "INFO" mock_get_settings.return_value = mock_settings mock_server = Mock() mock_app = Mock() mock_server.get_app.return_value = mock_app mock_create_app.return_value = mock_server with patch("src.main.logger") as mock_logger: main() # Verify startup logging was called mock_logger.info.assert_called() # Check the startup log message startup_log_call = None for call in mock_logger.info.call_args_list: if "Starting API Aggregator MCP Server" in call[0][0]: startup_log_call = call break assert startup_log_call is not None class TestMainIntegration: """Integration test cases for main module.""" @patch("src.main.uvicorn.run") @patch("src.main.validate_api_keys") def test_full_app_creation_flow(self, mock_validate_api_keys, mock_uvicorn_run): """Test the full app creation flow with real components.""" # Mock API keys being available mock_validate_api_keys.return_value = { "weather": True, "news": True, "stock": True, } # Mock settings with environment variables with patch.dict(os.environ, { "MCP_SERVER_HOST": "test-host", "MCP_SERVER_PORT": "9999", "MCP_SERVER_DEBUG": "true", "OPENWEATHER_API_KEY": "test-weather", "NEWS_API_KEY": "test-news", "ALPHA_VANTAGE_API_KEY": "test-stock", }, clear=True): # This should work end-to-end without mocking internal components main() # Verify uvicorn was called mock_uvicorn_run.assert_called_once() # Verify the call arguments include our test settings call_args = mock_uvicorn_run.call_args assert call_args[1]["host"] == "test-host" assert call_args[1]["port"] == 9999 assert call_args[1]["reload"] is True # debug=true def test_app_creation_without_mocking_settings(self): """Test app creation using real settings (but mocked API validation).""" with patch("src.main.validate_api_keys") as mock_validate: mock_validate.return_value = { "weather": False, "news": False, "stock": False, } # This should create a real MCPServer instance app = create_app() # Verify it's a real MCPServer assert isinstance(app, MCPServer) assert hasattr(app, '_tools') assert hasattr(app, '_handlers') assert hasattr(app, 'app') # FastAPI app # Should have no tools registered due to no API keys assert len(app._tools) == 0 assert len(app._handlers) == 0

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/mfang0126/api-aggregator-MCPServer'

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