ai-robot-core/ai-service/tests/test_routing_config.py

254 lines
9.1 KiB
Python

"""
Unit tests for Routing Configuration.
[AC-AISVC-RES-01~15] Tests for strategy routing configuration models.
"""
import pytest
from app.services.retrieval.routing_config import (
RagRuntimeMode,
StrategyType,
RoutingConfig,
StrategyContext,
StrategyResult,
)
class TestStrategyType:
"""[AC-AISVC-RES-01,02] Tests for StrategyType enum."""
def test_strategy_type_default(self):
"""[AC-AISVC-RES-01] Default strategy type should exist."""
assert StrategyType.DEFAULT.value == "default"
def test_strategy_type_enhanced(self):
"""[AC-AISVC-RES-02] Enhanced strategy type should exist."""
assert StrategyType.ENHANCED.value == "enhanced"
def test_strategy_type_from_string(self):
"""Should create StrategyType from string."""
assert StrategyType("default") == StrategyType.DEFAULT
assert StrategyType("enhanced") == StrategyType.ENHANCED
class TestRagRuntimeMode:
"""[AC-AISVC-RES-09,10,11] Tests for RagRuntimeMode enum."""
def test_mode_direct(self):
"""[AC-AISVC-RES-09] Direct mode should exist."""
assert RagRuntimeMode.DIRECT.value == "direct"
def test_mode_react(self):
"""[AC-AISVC-RES-10] React mode should exist."""
assert RagRuntimeMode.REACT.value == "react"
def test_mode_auto(self):
"""[AC-AISVC-RES-11] Auto mode should exist."""
assert RagRuntimeMode.AUTO.value == "auto"
def test_mode_from_string(self):
"""Should create RagRuntimeMode from string."""
assert RagRuntimeMode("direct") == RagRuntimeMode.DIRECT
assert RagRuntimeMode("react") == RagRuntimeMode.REACT
assert RagRuntimeMode("auto") == RagRuntimeMode.AUTO
class TestRoutingConfig:
"""[AC-AISVC-RES-01~15] Tests for RoutingConfig."""
def test_default_config(self):
"""[AC-AISVC-RES-01] Default config should use default strategy and auto mode."""
config = RoutingConfig()
assert config.enabled is True
assert config.strategy == StrategyType.DEFAULT
assert config.rag_runtime_mode == RagRuntimeMode.AUTO
assert config.grayscale_percentage == 0.0
assert config.grayscale_allowlist == []
def test_config_with_custom_values(self):
"""[AC-AISVC-RES-02,03] Config should accept custom values."""
config = RoutingConfig(
enabled=False,
strategy=StrategyType.ENHANCED,
rag_runtime_mode=RagRuntimeMode.REACT,
grayscale_percentage=0.3,
grayscale_allowlist=["tenant_a", "tenant_b"],
)
assert config.enabled is False
assert config.strategy == StrategyType.ENHANCED
assert config.rag_runtime_mode == RagRuntimeMode.REACT
assert config.grayscale_percentage == 0.3
assert "tenant_a" in config.grayscale_allowlist
def test_should_use_enhanced_strategy_default(self):
"""[AC-AISVC-RES-01] Default strategy should not use enhanced."""
config = RoutingConfig()
assert config.should_use_enhanced_strategy("tenant_a") is False
def test_should_use_enhanced_strategy_explicit_enhanced(self):
"""[AC-AISVC-RES-02] Explicit enhanced strategy should use enhanced for all tenants."""
config = RoutingConfig(strategy=StrategyType.ENHANCED)
assert config.should_use_enhanced_strategy("tenant_a") is True
assert config.should_use_enhanced_strategy("tenant_b") is True
assert config.should_use_enhanced_strategy(None) is True
def test_should_fallback_direct_to_react_disabled(self):
"""[AC-AISVC-RES-14] Fallback should be disabled when configured."""
config = RoutingConfig(direct_fallback_on_low_confidence=False)
assert config.should_fallback_direct_to_react(0.1) is False
assert config.should_fallback_direct_to_react(0.0) is False
def test_should_fallback_direct_to_react_enabled(self):
"""[AC-AISVC-RES-14] Fallback should trigger on low confidence."""
config = RoutingConfig(
direct_fallback_on_low_confidence=True,
direct_fallback_confidence_threshold=0.4,
)
assert config.should_fallback_direct_to_react(0.3) is True
assert config.should_fallback_direct_to_react(0.4) is False
assert config.should_fallback_direct_to_react(0.5) is False
def test_should_trigger_react_in_auto_mode_low_confidence(self):
"""[AC-AISVC-RES-12] Low confidence should trigger react in auto mode."""
config = RoutingConfig(
react_trigger_confidence_threshold=0.6,
)
assert config.should_trigger_react_in_auto_mode(
confidence=0.5, complexity_score=0.3
) is True
assert config.should_trigger_react_in_auto_mode(
confidence=0.7, complexity_score=0.3
) is False
def test_should_trigger_react_in_auto_mode_high_complexity(self):
"""[AC-AISVC-RES-13] High complexity should trigger react in auto mode."""
config = RoutingConfig(
react_trigger_complexity_score=0.5,
)
assert config.should_trigger_react_in_auto_mode(
confidence=0.8, complexity_score=0.6
) is True
assert config.should_trigger_react_in_auto_mode(
confidence=0.8, complexity_score=0.4
) is False
def test_validate_valid_config(self):
"""[AC-AISVC-RES-06] Valid config should pass validation."""
config = RoutingConfig()
is_valid, errors = config.validate()
assert is_valid is True
assert len(errors) == 0
def test_validate_invalid_grayscale_percentage(self):
"""[AC-AISVC-RES-06] Invalid grayscale percentage should fail validation."""
config = RoutingConfig(grayscale_percentage=1.5)
is_valid, errors = config.validate()
assert is_valid is False
assert any("grayscale_percentage" in e for e in errors)
def test_validate_invalid_confidence_threshold(self):
"""[AC-AISVC-RES-06] Invalid confidence threshold should fail validation."""
config = RoutingConfig(react_trigger_confidence_threshold=1.5)
is_valid, errors = config.validate()
assert is_valid is False
assert any("react_trigger_confidence_threshold" in e for e in errors)
def test_validate_invalid_react_max_steps(self):
"""[AC-AISVC-RES-06] Invalid react max steps should fail validation."""
config = RoutingConfig(react_max_steps=2)
is_valid, errors = config.validate()
assert is_valid is False
assert any("react_max_steps" in e for e in errors)
def test_validate_invalid_performance_budget(self):
"""[AC-AISVC-RES-06] Invalid performance budget should fail validation."""
config = RoutingConfig(performance_budget_ms=500)
is_valid, errors = config.validate()
assert is_valid is False
assert any("performance_budget_ms" in e for e in errors)
class TestStrategyContext:
"""[AC-AISVC-RES-01~15] Tests for StrategyContext."""
def test_context_creation(self):
"""Should create context with all fields."""
ctx = StrategyContext(
tenant_id="tenant_a",
query="Test query",
metadata_filter={"category": "product"},
metadata_confidence=0.8,
complexity_score=0.3,
kb_ids=["kb_1", "kb_2"],
top_k=10,
)
assert ctx.tenant_id == "tenant_a"
assert ctx.query == "Test query"
assert ctx.metadata_filter == {"category": "product"}
assert ctx.metadata_confidence == 0.8
assert ctx.complexity_score == 0.3
assert ctx.kb_ids == ["kb_1", "kb_2"]
assert ctx.top_k == 10
def test_context_minimal(self):
"""Should create context with minimal fields."""
ctx = StrategyContext(tenant_id="tenant_a", query="Test query")
assert ctx.tenant_id == "tenant_a"
assert ctx.query == "Test query"
assert ctx.metadata_filter is None
assert ctx.metadata_confidence == 1.0
assert ctx.complexity_score == 0.0
assert ctx.kb_ids is None
assert ctx.top_k == 5
class TestStrategyResult:
"""[AC-AISVC-RES-01,02] Tests for StrategyResult."""
def test_result_creation(self):
"""Should create result with all fields."""
result = StrategyResult(
strategy=StrategyType.ENHANCED,
mode=RagRuntimeMode.REACT,
should_fallback=True,
fallback_reason="Low confidence",
diagnostics={"key": "value"},
)
assert result.strategy == StrategyType.ENHANCED
assert result.mode == RagRuntimeMode.REACT
assert result.should_fallback is True
assert result.fallback_reason == "Low confidence"
assert result.diagnostics == {"key": "value"}
def test_result_defaults(self):
"""Should create result with default values."""
result = StrategyResult(
strategy=StrategyType.DEFAULT,
mode=RagRuntimeMode.AUTO,
)
assert result.should_fallback is False
assert result.fallback_reason is None
assert result.diagnostics == {}