from types import SimpleNamespace import pytest from yuxi.knowledge.eval import service as eval_service_module from yuxi.knowledge.eval.service import EvaluationService, build_evaluation_run_name class FakeEvaluationRepository: def __init__(self): self.created_dataset = None self.updated_dataset = None self.dataset = None self.created_run = None async def create_dataset(self, payload): self.created_dataset = payload async def update_dataset(self, dataset_id, payload): self.updated_dataset = (dataset_id, payload) async def get_dataset(self, dataset_id): return self.dataset async def create_run(self, payload): self.created_run = payload class FakeChunkRepository: def __init__(self, indexed_count): self.indexed_count = indexed_count async def count_graph_indexed_by_kb_id(self, kb_id): return self.indexed_count class FakeKnowledgeBaseRepository: async def get_by_kb_id(self, kb_id): return SimpleNamespace(query_params={"options": {"top_k": 3}}) @pytest.mark.asyncio async def test_generate_dataset_saves_generation_params(monkeypatch): async def fake_enqueue(**kwargs): return SimpleNamespace(id="task_1") monkeypatch.setattr(eval_service_module.tasker, "enqueue", fake_enqueue) service = EvaluationService() service.eval_repo = FakeEvaluationRepository() service.chunk_repo = FakeChunkRepository(indexed_count=1) result = await service.generate_dataset( kb_id="db_1", name="dataset", description="desc", count=2, neighbors_count=3, concurrency_count=4, llm_model_spec="test:model", generation_mode="graph_enhanced", graph_expand_top_k=2, created_by="user_1", ) assert result["task_id"] == "task_1" params = service.eval_repo.created_dataset["build_metadata"]["params"] assert params["generation_mode"] == "graph_enhanced" assert params["graph_expand_top_k"] == 2 updated_metadata = service.eval_repo.updated_dataset[1]["build_metadata"] assert updated_metadata["params"] == params @pytest.mark.asyncio async def test_generate_dataset_rejects_graph_mode_without_indexed_chunks(): service = EvaluationService() service.eval_repo = FakeEvaluationRepository() service.chunk_repo = FakeChunkRepository(indexed_count=0) with pytest.raises(ValueError, match="尚未完成图索引"): await service.generate_dataset( kb_id="db_1", name="dataset", description="desc", count=2, neighbors_count=3, concurrency_count=4, llm_model_spec="test:model", generation_mode="graph_enhanced", graph_expand_top_k=1, created_by="user_1", ) assert service.eval_repo.created_dataset is None def test_build_evaluation_run_name_uses_eval_date_hash_format(): name = build_evaluation_run_name(hash_value="abcdef12") assert name.startswith("eval-") assert name.endswith("-abcdef") assert len(name.split("-")[1]) == 8 @pytest.mark.asyncio async def test_run_evaluation_saves_custom_name(monkeypatch): async def fake_enqueue(**kwargs): return SimpleNamespace(id="task_1") monkeypatch.setattr(eval_service_module.tasker, "enqueue", fake_enqueue) repo = FakeEvaluationRepository() repo.dataset = SimpleNamespace( dataset_id="dataset_1", kb_id="db_1", name="dataset", item_count=2, build_metadata={"status": "completed"}, ) service = EvaluationService() service.eval_repo = repo service.kb_repo = FakeKnowledgeBaseRepository() run_id = await service.run_evaluation( kb_id="db_1", dataset_id="dataset_1", name=" 回归评估 ", model_config={"answer_llm": "test:model"}, created_by="user_1", ) assert run_id.startswith("run_") assert repo.created_run["name"] == "回归评估" assert repo.created_run["retrieval_config"]["top_k"] == 3 assert repo.created_run["retrieval_config"]["answer_llm"] == "test:model"