from types import SimpleNamespace import pytest from fastapi import HTTPException from yuxi.knowledge.utils import sample_question_utils as sq def test_parse_sample_questions_content_strips_json_fence(): questions = sq.parse_sample_questions_content('```json\n{"questions": ["什么是测试?"]}\n```') assert questions == ["什么是测试?"] def test_parse_sample_questions_content_rejects_invalid_payload(): with pytest.raises(ValueError, match="问题格式"): sq.parse_sample_questions_content('{"items": []}') @pytest.mark.asyncio async def test_generate_database_sample_questions_rejects_empty_files(monkeypatch): class FakeKnowledgeBase: async def get_database_info(self, kb_id: str, include_files: bool = False) -> dict: return {"name": "空知识库", "kb_type": "milvus", "files": {}} monkeypatch.setattr(sq, "knowledge_base", FakeKnowledgeBase()) monkeypatch.setattr( sq.KnowledgeBaseFactory, "get_kb_class", lambda _kb_type: SimpleNamespace(supports_documents=True), ) with pytest.raises(HTTPException) as exc_info: await sq.generate_database_sample_questions("kb_1") assert exc_info.value.status_code == 400 assert "没有文件" in exc_info.value.detail @pytest.mark.asyncio async def test_generate_database_sample_questions_saves_and_returns_questions(monkeypatch): saved: dict = {} class FakeKnowledgeBase: async def get_database_info(self, kb_id: str, include_files: bool = False) -> dict: return { "name": "测试知识库", "kb_type": "milvus", "files": {"file_1": {"filename": "demo.md", "file_type": "md"}}, } class FakeModel: async def call(self, messages, stream: bool = False): assert messages[0]["role"] == "system" assert "demo.md" in messages[1]["content"] return SimpleNamespace(content='{"questions": ["如何使用 demo?"]}') class FakeRepository: async def update(self, kb_id: str, data: dict) -> None: saved[kb_id] = data["sample_questions"] async def get_by_kb_id(self, kb_id: str): return SimpleNamespace(name="测试知识库", sample_questions=saved.get(kb_id)) monkeypatch.setattr(sq, "knowledge_base", FakeKnowledgeBase()) monkeypatch.setattr( sq.KnowledgeBaseFactory, "get_kb_class", lambda _kb_type: SimpleNamespace(supports_documents=True), ) monkeypatch.setattr(sq, "select_model", lambda model_spec: FakeModel()) monkeypatch.setattr(sq, "KnowledgeBaseRepository", lambda: FakeRepository()) generated = await sq.generate_database_sample_questions("kb_1", count=1) stored = await sq.get_database_sample_questions("kb_1") assert generated["questions"] == ["如何使用 demo?"] assert generated["count"] == 1 assert stored["questions"] == ["如何使用 demo?"] @pytest.mark.asyncio async def test_generate_database_sample_questions_maps_invalid_json(monkeypatch): class FakeKnowledgeBase: async def get_database_info(self, kb_id: str, include_files: bool = False) -> dict: return { "name": "测试知识库", "kb_type": "milvus", "files": {"file_1": {"filename": "demo.md", "file_type": "md"}}, } class FakeModel: async def call(self, messages, stream: bool = False): return SimpleNamespace(content="not json") monkeypatch.setattr(sq, "knowledge_base", FakeKnowledgeBase()) monkeypatch.setattr( sq.KnowledgeBaseFactory, "get_kb_class", lambda _kb_type: SimpleNamespace(supports_documents=True), ) monkeypatch.setattr(sq, "select_model", lambda model_spec: FakeModel()) with pytest.raises(HTTPException) as exc_info: await sq.generate_database_sample_questions("kb_1") assert exc_info.value.status_code == 500 assert "AI返回格式错误" in exc_info.value.detail