"""Tests for configuration management."""
import os
import pytest
from unittest.mock import patch
from src.utils.config import Settings, get_settings, validate_api_keys
class TestSettings:
"""Test cases for Settings class."""
def test_default_settings(self):
"""Test default settings values."""
# Clear environment to test actual defaults
with patch.dict(os.environ, {}, clear=True):
settings = Settings()
assert settings.host == "localhost"
assert settings.port == 8000
assert settings.debug is False
assert settings.openweather_api_key is None
assert settings.news_api_key is None
assert settings.alpha_vantage_api_key is None
assert settings.auth_enabled is False
assert settings.api_key is None
assert settings.log_level == "INFO"
def test_settings_with_env_vars(self):
"""Test settings loaded from environment variables."""
env_vars = {
"MCP_SERVER_HOST": "0.0.0.0",
"MCP_SERVER_PORT": "9000",
"MCP_SERVER_DEBUG": "true",
"OPENWEATHER_API_KEY": "weather_key_123",
"NEWS_API_KEY": "news_key_456",
"ALPHA_VANTAGE_API_KEY": "stock_key_789",
"MCP_AUTH_ENABLED": "true",
"MCP_API_KEY": "auth_key_abc",
"LOG_LEVEL": "DEBUG",
}
with patch.dict(os.environ, env_vars):
settings = Settings()
assert settings.host == "0.0.0.0"
assert settings.port == 9000
assert settings.debug is True
assert settings.openweather_api_key == "weather_key_123"
assert settings.news_api_key == "news_key_456"
assert settings.alpha_vantage_api_key == "stock_key_789"
assert settings.auth_enabled is True
assert settings.api_key == "auth_key_abc"
assert settings.log_level == "DEBUG"
def test_settings_with_partial_env_vars(self):
"""Test settings with only some environment variables set."""
env_vars = {
"OPENWEATHER_API_KEY": "weather_only",
"MCP_SERVER_PORT": "3000",
}
with patch.dict(os.environ, env_vars, clear=True):
settings = Settings()
# Should use env values where provided
assert settings.openweather_api_key == "weather_only"
assert settings.port == 3000
# Should use defaults for others
assert settings.host == "localhost"
assert settings.debug is False
assert settings.news_api_key is None
assert settings.alpha_vantage_api_key is None
def test_settings_type_conversion(self):
"""Test that environment variables are properly converted to correct types."""
env_vars = {
"MCP_SERVER_PORT": "8080", # String that should become int
"MCP_SERVER_DEBUG": "false", # String that should become bool
"MCP_AUTH_ENABLED": "1", # String that should become bool
}
with patch.dict(os.environ, env_vars):
settings = Settings()
assert isinstance(settings.port, int)
assert settings.port == 8080
assert isinstance(settings.debug, bool)
assert settings.debug is False
assert isinstance(settings.auth_enabled, bool)
assert settings.auth_enabled is True
def test_settings_case_insensitive(self):
"""Test that settings are case insensitive."""
# The Config class has case_sensitive = False
env_vars = {
"openweather_api_key": "lower_case_key", # lowercase
"MCP_SERVER_HOST": "UPPER_CASE_HOST", # uppercase
}
with patch.dict(os.environ, env_vars):
settings = Settings()
# Should work regardless of case
assert settings.openweather_api_key == "lower_case_key"
assert settings.host == "UPPER_CASE_HOST"
class TestConfigFunctions:
"""Test cases for configuration utility functions."""
def test_get_settings_returns_settings_instance(self):
"""Test that get_settings returns a Settings instance."""
settings = get_settings()
assert isinstance(settings, Settings)
@patch("src.utils.config.settings")
def test_get_settings_returns_global_instance(self, mock_settings):
"""Test that get_settings returns the global settings instance."""
result = get_settings()
assert result == mock_settings
def test_validate_api_keys_all_missing(self):
"""Test API key validation when all keys are missing."""
with patch.dict(os.environ, {}, clear=True):
settings = Settings()
with patch("src.utils.config.settings", settings):
result = validate_api_keys()
assert result == {
"weather": False,
"news": False,
"stock": False,
}
def test_validate_api_keys_all_present(self):
"""Test API key validation when all keys are present."""
env_vars = {
"OPENWEATHER_API_KEY": "weather_key",
"NEWS_API_KEY": "news_key",
"ALPHA_VANTAGE_API_KEY": "stock_key",
}
with patch.dict(os.environ, env_vars):
settings = Settings()
with patch("src.utils.config.settings", settings):
result = validate_api_keys()
assert result == {
"weather": True,
"news": True,
"stock": True,
}
def test_validate_api_keys_partial(self):
"""Test API key validation with only some keys present."""
env_vars = {
"OPENWEATHER_API_KEY": "weather_key",
"ALPHA_VANTAGE_API_KEY": "stock_key",
# NEWS_API_KEY is missing
}
with patch.dict(os.environ, env_vars):
settings = Settings()
with patch("src.utils.config.settings", settings):
result = validate_api_keys()
assert result == {
"weather": True,
"news": False,
"stock": True,
}
def test_validate_api_keys_empty_strings(self):
"""Test API key validation with empty string values."""
env_vars = {
"OPENWEATHER_API_KEY": "",
"NEWS_API_KEY": " ", # Whitespace only
"ALPHA_VANTAGE_API_KEY": "valid_key",
}
with patch.dict(os.environ, env_vars):
settings = Settings()
with patch("src.utils.config.settings", settings):
result = validate_api_keys()
# Empty strings and whitespace should be considered False
assert result == {
"weather": False,
"news": True, # Whitespace is truthy in Python
"stock": True,
}