""" tests/test_caller_registry.py ───────────────────────────────────────────────────────────────── Operation Ollama-First v5.0 / Phase 16 — caller_registry 集中管理驗證 驗證面: T1. CALLER_REGISTRY 含 ADR-028 列舉的 30+ caller T2. is_known_caller 對白名單回 True / 未知回 False T3. assert_known_caller(strict=False) → log warning 不 raise T4. assert_known_caller(strict=True) → 未知 raise ValueError T5. list_callers_by_service 分組正確 T6. ai_call_logger 整合:未知 caller 不阻擋(log warning) """ import logging import pytest def test_registry_contains_core_callers(): """ADR-028 白名單核心 caller 必在 registry""" from services.llm_caller_registry import CALLER_REGISTRY must_have = { # Hermes 'hermes_analyst', 'hermes_intent', # OpenClaw 'openclaw_daily', 'openclaw_weekly', 'openclaw_monthly', 'openclaw_meta', 'openclaw_qa', 'openclaw_qa_gemini_fallback', 'openclaw_qa_nim', 'openclaw_daily_gemini_fallback', 'openclaw_weekly_gemini_fallback', 'openclaw_monthly_gemini_fallback', 'openclaw_meta_gemini_fallback', 'openclaw_daily_insight_gemini_fallback', 'openclaw_daily_nim', 'openclaw_weekly_nim', 'openclaw_monthly_nim', 'openclaw_meta_nim', 'openclaw_daily_insight_nim', # MCP 'mcp_l1_grounding', 'mcp_collector', # Code Review 'code_review_hermes', 'code_review_openclaw', 'code_review_elephant', # NemoTron / EA 'nemotron_dispatch', 'ea_engine', # PPT 'ppt_gemini', 'ppt_ollama', 'ppt_nim', 'ppt_vision', # KM Embedding 'km_embedding_worker', 'km_embedding_realtime', # Sales / Trend 'sales_copy', 'trend_match', 'trend_qa', 'product_insights', # Bot 'openclaw_bot_main', 'openclaw_bot_gemini', 'openclaw_bot_nim', 'openclaw_bot_image', 'openclaw_bot_image_gemini', } missing = must_have - CALLER_REGISTRY assert not missing, f"registry 缺 {len(missing)} 個關鍵 caller: {missing}" def test_is_known_caller(): from services.llm_caller_registry import is_known_caller assert is_known_caller('hermes_analyst') is True assert is_known_caller('openclaw_qa') is True assert is_known_caller('openclaw_qa_gemini_fallback') is True assert is_known_caller('openclaw_qa_nim') is True assert is_known_caller('not_a_real_caller') is False assert is_known_caller('') is False assert is_known_caller('GeMiNi_Caller_Wrong_Case') is False def test_assert_known_caller_strict_false_only_warns(caplog): """strict=False(預設)→ 不在 registry 只 log warning""" from services.llm_caller_registry import assert_known_caller with caplog.at_level(logging.WARNING): assert_known_caller('totally_made_up_caller', strict=False) # 應有 warning warnings = [r for r in caplog.records if r.levelno >= logging.WARNING] assert len(warnings) >= 1 assert 'unknown caller' in warnings[0].message.lower() or \ 'totally_made_up_caller' in warnings[0].message def test_assert_known_caller_strict_true_raises(): from services.llm_caller_registry import assert_known_caller with pytest.raises(ValueError, match='unknown caller'): assert_known_caller('definitely_not_real', strict=True) def test_assert_known_caller_passes_for_real_caller(): """合法 caller → 不 raise / 不 warn""" from services.llm_caller_registry import assert_known_caller # 不該 raise assert_known_caller('hermes_analyst', strict=True) assert_known_caller('openclaw_qa', strict=False) def test_list_callers_by_service_structure(): from services.llm_caller_registry import list_callers_by_service, CALLER_REGISTRY grouped = list_callers_by_service() expected_groups = {'hermes', 'openclaw', 'openclaw_bot', 'mcp', 'code_review', 'ppt', 'tg_bot', 'km_embedding', 'sales_trend', 'misc'} assert expected_groups.issubset(grouped.keys()) # 每組至少 1 個 for group, callers in grouped.items(): assert isinstance(callers, list) assert len(callers) >= 1, f"group '{group}' 是空的" # hermes 至少含 hermes_analyst assert 'hermes_analyst' in grouped['hermes'] def test_ai_call_logger_integration_does_not_block_unknown_caller(caplog): """ai_call_logger 收到 unknown caller 應 log warning 但不阻擋 context manager""" import os os.environ['AI_CALL_LOGGING_ENABLED'] = 'false' # 跳過 DB 寫入 try: from services.ai_call_logger import log_ai_call with caplog.at_level(logging.WARNING): with log_ai_call( caller='unknown_test_caller_xyz', # 故意不在 registry provider='gcp_ollama', model='hermes3:latest', ) as ctx: ctx.set_tokens(input=100, output=50) # context manager 不 raise,正常結束 # 應該有 warning(caller 不在 registry) warnings = [r for r in caplog.records if r.levelno >= logging.WARNING] assert any('unknown_test_caller' in r.message.lower() or 'unknown caller' in r.message.lower() for r in warnings), \ f"應 warn unknown caller,實際 warnings: {[r.message for r in warnings]}" finally: os.environ.pop('AI_CALL_LOGGING_ENABLED', None) def test_registry_is_immutable_frozenset(): """CALLER_REGISTRY 是 frozenset 不可變動""" from services.llm_caller_registry import CALLER_REGISTRY assert isinstance(CALLER_REGISTRY, frozenset) with pytest.raises(AttributeError): CALLER_REGISTRY.add('attempted_mutation') # type: ignore