mirror of
https://github.com/hoshikawa2/compass_backoffice.git
synced 2026-07-09 13:54:20 +00:00
440 lines
14 KiB
Python
440 lines
14 KiB
Python
"""
|
|
Unit tests for configuration module.
|
|
|
|
Tests specific examples and edge cases for configuration loading and validation.
|
|
"""
|
|
|
|
import pytest
|
|
import tempfile
|
|
import os
|
|
from pathlib import Path
|
|
from pydantic import ValidationError
|
|
|
|
from src.core.config import Settings, LLMConfig, AgentConfig
|
|
|
|
|
|
class TestSettings:
|
|
"""Test Settings class."""
|
|
|
|
def test_settings_with_required_fields(self):
|
|
"""Test that Settings can be created with required fields."""
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4"
|
|
)
|
|
|
|
assert settings.LLM_PROVIDER == "openai"
|
|
assert settings.LLM_MODEL == "gpt-4"
|
|
assert settings.APP_NAME == "Agent Microservice" # default value
|
|
assert settings.DEBUG is False # default value
|
|
assert settings.CLASSIFICATION_LLM_MODEL == "bo_gptoss20b_dev"
|
|
assert settings.CLASSIFICATION_LLM_TEMPERATURE == 0.3
|
|
|
|
def test_settings_classification_custom_values(self):
|
|
"""Test that Settings can be created with custom classification LLM values."""
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
CLASSIFICATION_LLM_MODEL="custom_model",
|
|
CLASSIFICATION_LLM_TEMPERATURE=0.5,
|
|
CLASSIFICATION_LLM_MAX_TOKENS=512,
|
|
CLASSIFICATION_LLM_TOP_P=0.9
|
|
)
|
|
|
|
assert settings.CLASSIFICATION_LLM_MODEL == "custom_model"
|
|
assert settings.CLASSIFICATION_LLM_TEMPERATURE == 0.5
|
|
assert settings.CLASSIFICATION_LLM_MAX_TOKENS == 512
|
|
assert settings.CLASSIFICATION_LLM_TOP_P == 0.9
|
|
|
|
def test_settings_missing_required_field_llm_provider(self):
|
|
"""Test that missing LLM_PROVIDER raises ValidationError."""
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(LLM_MODEL="gpt-4")
|
|
|
|
errors = exc_info.value.errors()
|
|
assert any(error['loc'] == ('LLM_PROVIDER',) for error in errors)
|
|
|
|
def test_settings_missing_required_field_llm_model(self):
|
|
"""Test that missing LLM_MODEL raises ValidationError."""
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(LLM_PROVIDER="openai")
|
|
|
|
errors = exc_info.value.errors()
|
|
assert any(error['loc'] == ('LLM_MODEL',) for error in errors)
|
|
|
|
def test_settings_invalid_llm_provider(self):
|
|
"""Test that invalid LLM_PROVIDER raises ValidationError."""
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(
|
|
LLM_PROVIDER="invalid_provider",
|
|
LLM_MODEL="gpt-4"
|
|
)
|
|
|
|
errors = exc_info.value.errors()
|
|
assert any("LLM_PROVIDER" in str(error) for error in errors)
|
|
|
|
def test_settings_valid_providers(self):
|
|
"""Test that valid providers are accepted."""
|
|
for provider in ["openai", "anthropic"]:
|
|
settings = Settings(
|
|
LLM_PROVIDER=provider,
|
|
LLM_MODEL="test-model"
|
|
)
|
|
assert settings.LLM_PROVIDER == provider
|
|
|
|
def test_settings_temperature_validation(self):
|
|
"""Test temperature validation."""
|
|
# Valid temperature
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LLM_TEMPERATURE=1.5
|
|
)
|
|
assert settings.LLM_TEMPERATURE == 1.5
|
|
|
|
# Temperature too low
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LLM_TEMPERATURE=-0.1
|
|
)
|
|
|
|
# Temperature too high
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LLM_TEMPERATURE=2.1
|
|
)
|
|
|
|
def test_settings_from_yaml_valid(self):
|
|
"""Test loading settings from valid YAML file."""
|
|
yaml_content = """
|
|
APP_NAME: "Test Agent"
|
|
VERSION: "2.0.0"
|
|
DEBUG: true
|
|
LLM_PROVIDER: "openai"
|
|
LLM_MODEL: "gpt-3.5-turbo"
|
|
LLM_TEMPERATURE: 0.5
|
|
HOST: "127.0.0.1"
|
|
PORT: 9000
|
|
LOG_LEVEL: "DEBUG"
|
|
"""
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
|
f.write(yaml_content)
|
|
temp_path = f.name
|
|
|
|
try:
|
|
settings = Settings.from_yaml(temp_path)
|
|
|
|
assert settings.APP_NAME == "Test Agent"
|
|
assert settings.VERSION == "2.0.0"
|
|
assert settings.DEBUG is True
|
|
assert settings.LLM_PROVIDER == "openai"
|
|
assert settings.LLM_MODEL == "gpt-3.5-turbo"
|
|
assert settings.LLM_TEMPERATURE == 0.5
|
|
assert settings.HOST == "127.0.0.1"
|
|
assert settings.PORT == 9000
|
|
assert settings.LOG_LEVEL == "DEBUG"
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
def test_settings_from_yaml_missing_required(self):
|
|
"""Test that loading YAML without required fields raises error."""
|
|
yaml_content = """
|
|
APP_NAME: "Test Agent"
|
|
VERSION: "2.0.0"
|
|
"""
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
|
f.write(yaml_content)
|
|
temp_path = f.name
|
|
|
|
try:
|
|
with pytest.raises(ValidationError):
|
|
Settings.from_yaml(temp_path)
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
def test_settings_from_yaml_file_not_found(self):
|
|
"""Test that loading from non-existent file raises FileNotFoundError."""
|
|
with pytest.raises(FileNotFoundError):
|
|
Settings.from_yaml("/nonexistent/path/config.yaml")
|
|
|
|
def test_settings_from_yaml_empty_file(self):
|
|
"""Test loading from empty YAML file."""
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
|
f.write("")
|
|
temp_path = f.name
|
|
|
|
try:
|
|
with pytest.raises(ValidationError):
|
|
Settings.from_yaml(temp_path)
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
def test_settings_log_level_validation(self):
|
|
"""Test log level validation."""
|
|
# Valid log levels
|
|
for level in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_LEVEL=level
|
|
)
|
|
assert settings.LOG_LEVEL == level
|
|
|
|
# Case insensitive
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_LEVEL="debug"
|
|
)
|
|
assert settings.LOG_LEVEL == "DEBUG"
|
|
|
|
# Invalid log level
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_LEVEL="INVALID"
|
|
)
|
|
|
|
def test_settings_log_format_validation(self):
|
|
"""Test log format validation."""
|
|
# Valid formats
|
|
for fmt in ["json", "text"]:
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_FORMAT=fmt
|
|
)
|
|
assert settings.LOG_FORMAT == fmt
|
|
|
|
# Case insensitive
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_FORMAT="JSON"
|
|
)
|
|
assert settings.LOG_FORMAT == "json"
|
|
|
|
# Invalid format
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LOG_FORMAT="xml"
|
|
)
|
|
|
|
def test_settings_port_validation(self):
|
|
"""Test port number validation."""
|
|
# Valid port
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
PORT=8080
|
|
)
|
|
assert settings.PORT == 8080
|
|
|
|
# Port too low
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
PORT=0
|
|
)
|
|
|
|
# Port too high
|
|
with pytest.raises(ValidationError):
|
|
Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
PORT=65536
|
|
)
|
|
|
|
|
|
class TestLLMConfig:
|
|
"""Test LLMConfig model."""
|
|
|
|
def test_llm_config_valid(self):
|
|
"""Test creating valid LLMConfig."""
|
|
config = LLMConfig(
|
|
provider="openai",
|
|
model="gpt-4",
|
|
temperature=0.8,
|
|
max_tokens=1000
|
|
)
|
|
|
|
assert config.provider == "openai"
|
|
assert config.model == "gpt-4"
|
|
assert config.temperature == 0.8
|
|
assert config.max_tokens == 1000
|
|
|
|
def test_llm_config_default_temperature(self):
|
|
"""Test default temperature value."""
|
|
config = LLMConfig(
|
|
provider="openai",
|
|
model="gpt-4"
|
|
)
|
|
|
|
assert config.temperature == 0.7
|
|
|
|
def test_llm_config_invalid_provider(self):
|
|
"""Test that invalid provider raises error."""
|
|
with pytest.raises(ValidationError):
|
|
LLMConfig(
|
|
provider="invalid",
|
|
model="gpt-4"
|
|
)
|
|
|
|
def test_llm_config_temperature_bounds(self):
|
|
"""Test temperature boundary validation."""
|
|
# Valid boundaries
|
|
LLMConfig(provider="openai", model="gpt-4", temperature=0.0)
|
|
LLMConfig(provider="openai", model="gpt-4", temperature=2.0)
|
|
|
|
# Invalid boundaries
|
|
with pytest.raises(ValidationError):
|
|
LLMConfig(provider="openai", model="gpt-4", temperature=-0.1)
|
|
|
|
with pytest.raises(ValidationError):
|
|
LLMConfig(provider="openai", model="gpt-4", temperature=2.1)
|
|
|
|
def test_llm_config_max_tokens_validation(self):
|
|
"""Test max_tokens validation."""
|
|
# Valid max_tokens
|
|
config = LLMConfig(
|
|
provider="openai",
|
|
model="gpt-4",
|
|
max_tokens=100
|
|
)
|
|
assert config.max_tokens == 100
|
|
|
|
# None is valid
|
|
config = LLMConfig(
|
|
provider="openai",
|
|
model="gpt-4",
|
|
max_tokens=None
|
|
)
|
|
assert config.max_tokens is None
|
|
|
|
# Zero or negative is invalid
|
|
with pytest.raises(ValidationError):
|
|
LLMConfig(
|
|
provider="openai",
|
|
model="gpt-4",
|
|
max_tokens=0
|
|
)
|
|
|
|
|
|
class TestAgentConfig:
|
|
"""Test AgentConfig model."""
|
|
|
|
def test_agent_config_valid(self):
|
|
"""Test creating valid AgentConfig."""
|
|
config = AgentConfig(
|
|
name="Test Agent",
|
|
description="A test agent",
|
|
system_prompt="You are a test assistant",
|
|
tools=["tool1", "tool2"],
|
|
max_iterations=5
|
|
)
|
|
|
|
assert config.name == "Test Agent"
|
|
assert config.description == "A test agent"
|
|
assert config.system_prompt == "You are a test assistant"
|
|
assert config.tools == ["tool1", "tool2"]
|
|
assert config.max_iterations == 5
|
|
|
|
def test_agent_config_default_tools(self):
|
|
"""Test default empty tools list."""
|
|
config = AgentConfig(
|
|
name="Test Agent",
|
|
description="A test agent",
|
|
system_prompt="You are a test assistant"
|
|
)
|
|
|
|
assert config.tools == []
|
|
|
|
def test_agent_config_default_max_iterations(self):
|
|
"""Test default max_iterations value."""
|
|
config = AgentConfig(
|
|
name="Test Agent",
|
|
description="A test agent",
|
|
system_prompt="You are a test assistant"
|
|
)
|
|
|
|
assert config.max_iterations == 10
|
|
|
|
def test_agent_config_max_iterations_validation(self):
|
|
"""Test max_iterations must be positive."""
|
|
# Valid
|
|
AgentConfig(
|
|
name="Test Agent",
|
|
description="A test agent",
|
|
system_prompt="You are a test assistant",
|
|
max_iterations=1
|
|
)
|
|
|
|
# Invalid
|
|
with pytest.raises(ValidationError):
|
|
AgentConfig(
|
|
name="Test Agent",
|
|
description="A test agent",
|
|
system_prompt="You are a test assistant",
|
|
max_iterations=0
|
|
)
|
|
|
|
|
|
class TestSettingsConversion:
|
|
"""Test Settings conversion methods."""
|
|
|
|
def test_to_llm_config(self):
|
|
"""Test converting Settings to LLMConfig."""
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
LLM_TEMPERATURE=0.9,
|
|
LLM_MAX_TOKENS=2000
|
|
)
|
|
|
|
llm_config = settings.to_llm_config()
|
|
|
|
assert isinstance(llm_config, LLMConfig)
|
|
assert llm_config.provider == "openai"
|
|
assert llm_config.model == "gpt-4"
|
|
assert llm_config.temperature == 0.9
|
|
assert llm_config.max_tokens == 2000
|
|
|
|
def test_to_agent_config_with_all_fields(self):
|
|
"""Test converting Settings to AgentConfig when all fields present."""
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4",
|
|
AGENT_NAME="My Agent",
|
|
AGENT_DESCRIPTION="My agent description",
|
|
AGENT_SYSTEM_PROMPT="You are my agent",
|
|
AGENT_MAX_ITERATIONS=15
|
|
)
|
|
|
|
agent_config = settings.to_agent_config()
|
|
|
|
assert agent_config is not None
|
|
assert isinstance(agent_config, AgentConfig)
|
|
assert agent_config.name == "My Agent"
|
|
assert agent_config.description == "My agent description"
|
|
assert agent_config.system_prompt == "You are my agent"
|
|
assert agent_config.max_iterations == 15
|
|
|
|
def test_to_agent_config_missing_fields(self):
|
|
"""Test that to_agent_config returns None when fields missing."""
|
|
settings = Settings(
|
|
LLM_PROVIDER="openai",
|
|
LLM_MODEL="gpt-4"
|
|
)
|
|
|
|
agent_config = settings.to_agent_config()
|
|
|
|
assert agent_config is None
|