"""端到端集成测试.""" import tempfile import os import pytest from hermes_core.types import HERMES_DATA_DIR as _ORIG_DIR from hermes_core.querier import HermesClient pytestmark = pytest.mark.requires_embedder @pytest.fixture(autouse=True) def temp_data_dir(monkeypatch): """将 HERMES_DATA_DIR 重定向到临时目录。""" tmp = tempfile.mkdtemp() monkeypatch.setattr("hermes_core.types.HERMES_DATA_DIR", type(_ORIG_DIR)(tmp)) # Also patch all modules that import HERMES_DATA_DIR import hermes_core.db as db_module import hermes_core.trainer as trainer_module monkeypatch.setattr(db_module, "HERMES_DATA_DIR", type(_ORIG_DIR)(tmp)) monkeypatch.setattr(trainer_module, "HERMES_DATA_DIR", type(_ORIG_DIR)(tmp)) yield tmp import shutil shutil.rmtree(tmp, ignore_errors=True) class TestE2EFlow: def test_full_flow_record_query_refine(self): """完整链路:record → query → refine → query。""" client = HermesClient(user_id="u_e2e", agent_id="test-agent") # Step 1: 记录第二条(2 维) r1 = client.record( "后端API开发", [ {"key": "language", "value": "TypeScript", "context": "默认"}, {"key": "framework", "value": "Express", "context": "默认"}, ], ) assert r1["status"] == "recorded" # Step 2: 语义相似的 query 应匹配到 scope result = client.query("帮我写一个后端API服务") assert result.matched_scope is not None assert any(p.key == "language" and p.value == "TypeScript" for p in result.related_preferences) # Step 3: refine —— narrow from hermes_core.refiner import refine_scene from hermes_core.embedder import Embedder embedder = Embedder() ref = refine_scene("u_e2e", r1["id"], "Express REST API开发", "narrow", embedder) assert ref["status"] == "refined" # Step 4: query 现在应匹配到细化的 scope result2 = client.query("Express REST API服务端开发") assert result2.matched_scope is not None def test_dimension_constraint_blocks_lower_dim(self): """维度约束:低维记录应被拒绝。""" client = HermesClient(user_id="u_e2e_dim", agent_id="test") r1 = client.record( "数据处理", [ {"key": "language", "value": "Python", "context": ""}, {"key": "lib", "value": "Pandas", "context": ""}, {"key": "style", "value": "functional", "context": ""}, ], ) assert r1["status"] == "recorded" r2 = client.record( "数据处理", [{"key": "language", "value": "R", "context": ""}], ) assert r2["status"] == "rejected" assert "dimension" in r2["reason"].lower() def test_conversation_id_relaxes_constraint(self): """同会话内维度约束松弛。""" client = HermesClient(user_id="u_e2e_conv", agent_id="test") conv_id = "conv_e2e_001" r1 = client.record( "前端开发", [ {"key": "framework", "value": "React", "context": ""}, {"key": "language", "value": "TypeScript", "context": ""}, ], conversation_id=conv_id, ) assert r1["status"] == "recorded" r2 = client.record( "前端开发", [{"key": "testing", "value": "Vitest", "context": ""}], conversation_id=conv_id, ) assert r2["status"] == "recorded" # 同对话,不拒绝 def test_multiple_scopes_created_automatically(self): """不同话题自动创建不同 scope。""" client = HermesClient(user_id="u_e2e_multi", agent_id="test") r1 = client.record("后端API开发", [{"key": "lang", "value": "TS", "context": ""}]) r2 = client.record("周末去哪玩", [{"key": "pref", "value": "户外", "context": ""}]) assert r1["scope_id"] != r2["scope_id"] # 不同 scope assert r1["status"] == "recorded" assert r2["status"] == "recorded"