"""
单元测试:配置管理模块测试
"""
import pytest
import tempfile
import yaml
from pathlib import Path
from typing import Dict, Any, Generator, Generator
from src.percepta_mcp.config import (
AIProviderConfig,
BrowserConfig,
MCPServerConfig,
MonitoringConfig,
Settings,
get_default_settings
)
class TestAIProviderConfig:
"""测试AI提供商配置"""
def test_ai_provider_config_creation(self) -> None:
"""测试AI提供商配置创建"""
config = AIProviderConfig(
name="test-provider",
type="openai",
model="gpt-4",
api_key="test-key"
)
assert config.name == "test-provider"
assert config.type == "openai"
assert config.model == "gpt-4"
assert config.api_key == "test-key"
assert config.priority == 1 # 默认值
assert config.enabled is True # 默认值
def test_ai_provider_config_defaults(self) -> None:
"""测试AI提供商配置默认值"""
config = AIProviderConfig(
name="test",
type="openai",
model="gpt-4"
)
assert config.priority == 1
assert config.max_tokens == 4000
assert config.temperature == 0.7
assert config.timeout == 30
assert config.retry_attempts == 3
assert config.cost_per_token == 0.0
assert config.rate_limit == 60
assert config.enabled is True
def test_ai_provider_config_validation(self) -> None:
"""测试AI提供商配置验证"""
# 缺少必需字段应该失败
with pytest.raises((ValueError, TypeError)):
AIProviderConfig() # type: ignore
# 测试成功创建
config = AIProviderConfig(
name="test",
type="openai",
model="gpt-4",
temperature=0.5
)
assert config.temperature == 0.5
class TestBrowserConfig:
"""测试浏览器配置"""
def test_browser_config_defaults(self) -> None:
"""测试浏览器配置默认值"""
config = BrowserConfig()
assert config.browser_type == "chromium"
assert config.headless is True
assert config.timeout == 30000
assert config.viewport_width == 1920
assert config.viewport_height == 1080
assert config.user_agent is None
assert config.proxy is None
def test_browser_config_custom_values(self) -> None:
"""测试浏览器配置自定义值"""
config = BrowserConfig(
browser_type="firefox",
headless=False,
timeout=60000,
viewport_width=1280,
viewport_height=720,
user_agent="custom-agent"
)
assert config.browser_type == "firefox"
assert config.headless is False
assert config.timeout == 60000
assert config.viewport_width == 1280
assert config.viewport_height == 720
assert config.user_agent == "custom-agent"
class TestMCPServerConfig:
"""测试MCP服务器配置"""
def test_mcp_server_config_defaults(self) -> None:
"""测试MCP服务器配置默认值"""
config = MCPServerConfig()
assert config.host == "localhost"
assert config.port == 8080
assert config.transport == "stdio"
assert config.max_connections == 10
assert config.request_timeout == 30
class TestMonitoringConfig:
"""测试监控配置"""
def test_monitoring_config_defaults(self) -> None:
"""测试监控配置默认值"""
config = MonitoringConfig()
assert config.log_level == "INFO"
assert config.log_file == "logs/percepta_mcp.log"
assert config.enable_metrics is True
assert config.metrics_port == 9090
assert config.enable_devtools_capture is True
class TestSettings:
"""测试主设置类"""
def test_settings_creation(self) -> None:
"""测试设置创建"""
settings = Settings()
assert isinstance(settings.ai_providers, list)
assert settings.default_provider == "ollama"
assert isinstance(settings.browser, BrowserConfig)
assert isinstance(settings.mcp_server, MCPServerConfig)
assert isinstance(settings.monitoring, MonitoringConfig)
def test_settings_with_providers(self) -> None:
"""测试包含提供商的设置"""
provider_config = AIProviderConfig(
name="test-provider",
type="openai",
model="gpt-4"
)
settings = Settings(
ai_providers=[provider_config],
default_provider="test-provider"
)
assert len(settings.ai_providers) == 1
assert settings.ai_providers[0].name == "test-provider"
assert settings.default_provider == "test-provider"
def test_settings_yaml_round_trip(self) -> None:
"""测试YAML配置的往返转换"""
# 创建临时文件
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
temp_file = Path(f.name)
try:
# 创建测试配置
original_settings = Settings(
ai_providers=[
AIProviderConfig(
name="test-provider",
type="openai",
model="gpt-4",
api_key="test-key"
)
],
default_provider="test-provider"
)
# 保存到YAML
original_settings.save_to_yaml(str(temp_file))
# 从YAML加载
loaded_settings = Settings.load_from_yaml(str(temp_file))
# 验证数据一致性
assert len(loaded_settings.ai_providers) == 1
assert loaded_settings.ai_providers[0].name == "test-provider"
assert loaded_settings.ai_providers[0].type == "openai"
assert loaded_settings.ai_providers[0].model == "gpt-4"
assert loaded_settings.ai_providers[0].api_key == "test-key"
assert loaded_settings.default_provider == "test-provider"
finally:
# 清理临时文件
if temp_file.exists():
temp_file.unlink()
def test_settings_yaml_file_not_found(self) -> None:
"""测试YAML文件不存在的情况"""
with pytest.raises(FileNotFoundError):
Settings.load_from_yaml("nonexistent_file.yaml")
def test_settings_invalid_yaml(self) -> None:
"""测试无效YAML配置"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
# 写入无效的配置数据
yaml.dump({
"ai_providers": "invalid_value", # 应该是列表,但给了字符串
"invalid_field": "value"
}, f)
temp_file = Path(f.name)
try:
with pytest.raises(ValueError):
Settings.load_from_yaml(str(temp_file))
finally:
if temp_file.exists():
temp_file.unlink()
class TestGetDefaultSettings:
"""测试默认设置函数"""
def test_get_default_settings(self) -> None:
"""测试获取默认设置"""
settings = get_default_settings()
assert isinstance(settings, Settings)
assert len(settings.ai_providers) > 0
# 验证默认提供商(只有 Ollama 始终可用,其他需要 API 密钥)
provider_names = [p.name for p in settings.ai_providers]
assert "ollama-local" in provider_names
# 验证优先级设置
priorities = [p.priority for p in settings.ai_providers]
assert 1 in priorities # 最高优先级
def test_default_providers_configuration(self) -> None:
"""测试默认提供商配置"""
settings = get_default_settings()
# 查找ollama提供商(始终存在)
ollama_provider = next(
(p for p in settings.ai_providers if p.name == "ollama-local"),
None
)
assert ollama_provider is not None
assert ollama_provider.type == "ollama"
assert ollama_provider.base_url == "http://localhost:11434"
assert ollama_provider.cost_per_token == 0.0
# Pytest配置和fixtures
@pytest.fixture
def sample_config_data() -> Dict[str, Any]:
"""提供示例配置数据"""
return {
"ai_providers": [
{
"name": "test-openai",
"type": "openai",
"model": "gpt-4",
"api_key": "test-key",
"priority": 1,
"enabled": True
}
],
"default_provider": "test-openai",
"enable_ocr": True,
"enable_visual_analysis": True,
"enable_cost_tracking": False
}
@pytest.fixture
def temp_config_file(sample_config_data: Dict[str, Any]) -> Generator[Path, None, None]:
"""创建临时配置文件"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
yaml.dump(sample_config_data, f)
temp_file = Path(f.name)
yield temp_file
# 清理
if temp_file.exists():
temp_file.unlink()
class TestConfigurationIntegration:
"""配置集成测试"""
def test_load_from_temp_file(self, temp_config_file: Path) -> None:
"""测试从临时文件加载配置"""
settings = Settings.load_from_yaml(str(temp_config_file))
assert len(settings.ai_providers) == 1
assert settings.ai_providers[0].name == "test-openai"
assert settings.default_provider == "test-openai"
assert settings.enable_ocr is True
assert settings.enable_cost_tracking is False
if __name__ == "__main__":
pytest.main([__file__, "-v"])