Files
ai-contract-platform/backend/tests/test_knowledge_bases_api.py
T
2026-04-24 13:44:17 +08:00

242 lines
9.5 KiB
Python

import unittest
from fastapi import HTTPException
from fastapi.testclient import TestClient
from app.api.knowledge_bases import get_audit_log_service, get_knowledge_base_service, require_current_user
from app.main import app
class StubAuditLogService:
def __init__(self):
self.events = []
def record_event(self, **kwargs):
self.events.append(kwargs)
return kwargs
class StubKnowledgeBaseService:
def list_knowledge_bases(self, current_user, page, page_size):
if current_user["role"] != "admin":
raise HTTPException(status_code=403, detail="forbidden")
return {
"items": [
{
"id": "kb-123",
"name": "劳动合同知识库",
"description": "劳动用工条款",
"status": "active",
"document_count": 1,
"created_at": "2026-04-16T00:00:00+00:00",
"updated_at": "2026-04-16T00:00:00+00:00",
}
],
"page": page,
"page_size": page_size,
"total": 1,
}
def create_knowledge_base(self, current_user, name, description):
if current_user["role"] != "admin":
raise HTTPException(status_code=403, detail="forbidden")
return {
"id": "kb-123",
"name": name,
"description": description,
"status": "active",
"document_count": 0,
"created_at": "2026-04-16T00:00:00+00:00",
"updated_at": "2026-04-16T00:00:00+00:00",
}
def list_documents(self, current_user, knowledge_base_id, page, page_size):
if current_user["role"] != "admin":
raise HTTPException(status_code=403, detail="forbidden")
return {
"items": [
{
"id": "kbdoc-123",
"knowledge_base_id": knowledge_base_id,
"file_name": "rules.txt",
"mime_type": "text/plain",
"file_size": 12,
"status": "indexed",
"content_excerpt": "合同解除规则",
"extracted_text_length": 6,
"preview_truncated": False,
"created_at": "2026-04-16T00:00:00+00:00",
"current_stage": "indexed",
"current_stage_label": "已完成索引",
"status_detail": "文本提取与索引已完成,可直接用于检索和问答。",
"parse_status": "completed",
"index_status": "completed",
"failure_reason": None,
"next_action": "可直接进入问答,或继续补充更多制度与条款文档。",
},
{
"id": "kbdoc-456",
"knowledge_base_id": knowledge_base_id,
"file_name": "draft.docx",
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"file_size": 18,
"status": "processing",
"content_excerpt": None,
"extracted_text_length": 0,
"preview_truncated": False,
"created_at": "2026-04-16T00:10:00+00:00",
"current_stage": "parse",
"current_stage_label": "文本提取中",
"status_detail": "系统正在提取文本并写入检索索引。",
"parse_status": "processing",
"index_status": "blocked",
"failure_reason": "文本提取尚未完成,索引阶段暂时阻塞。",
"next_action": "请等待文本提取完成;提取成功后系统会继续进入索引阶段。",
}
],
"page": page,
"page_size": page_size,
"total": 2,
}
def upload_document(self, current_user, knowledge_base_id, file_name, mime_type, content):
if current_user["role"] != "admin":
raise HTTPException(status_code=403, detail="forbidden")
return {
"id": "kbdoc-123",
"knowledge_base_id": knowledge_base_id,
"file_name": file_name,
"mime_type": mime_type,
"file_size": len(content),
"status": "indexed",
"content_excerpt": content.decode("utf-8"),
"extracted_text_length": len(content.decode("utf-8")),
"preview_truncated": False,
"created_at": "2026-04-16T00:00:00+00:00",
"current_stage": "indexed",
"current_stage_label": "已完成索引",
"status_detail": "文本提取与索引已完成,可直接用于检索和问答。",
"parse_status": "completed",
"index_status": "completed",
"failure_reason": None,
"next_action": "可直接进入问答,或继续补充更多制度与条款文档。",
"error_message": None,
}
class KnowledgeBasesApiTestCase(unittest.TestCase):
def setUp(self):
self.audit_log_service = StubAuditLogService()
app.dependency_overrides[get_knowledge_base_service] = lambda: StubKnowledgeBaseService()
app.dependency_overrides[get_audit_log_service] = lambda: self.audit_log_service
self.client = TestClient(app)
def tearDown(self):
app.dependency_overrides.clear()
def test_admin_can_list_knowledge_bases(self):
app.dependency_overrides[require_current_user] = lambda: {
"id": "user-admin",
"tenant_id": "tenant-demo-001",
"role": "admin",
}
response = self.client.get("/api/v1/knowledge-bases")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["data"]["items"][0]["name"], "劳动合同知识库")
def test_admin_can_list_documents_with_blocked_index_stage(self):
app.dependency_overrides[require_current_user] = lambda: {
"id": "user-admin",
"tenant_id": "tenant-demo-001",
"role": "admin",
}
response = self.client.get("/api/v1/knowledge-bases/kb-123/documents")
self.assertEqual(response.status_code, 200)
items = response.json()["data"]["items"]
self.assertEqual(len(items), 2)
blocked_item = items[1]
self.assertEqual(blocked_item["current_stage"], "parse")
self.assertEqual(blocked_item["index_status"], "blocked")
self.assertEqual(blocked_item["failure_reason"], "文本提取尚未完成,索引阶段暂时阻塞。")
self.assertIn("继续进入索引阶段", blocked_item["next_action"])
def test_admin_can_create_knowledge_base(self):
app.dependency_overrides[require_current_user] = lambda: {
"id": "user-admin",
"tenant_id": "tenant-demo-001",
"role": "admin",
}
response = self.client.post(
"/api/v1/knowledge-bases",
data={"name": "采购合同知识库", "description": "采购模板与制度"},
)
self.assertEqual(response.status_code, 200)
body = response.json()
self.assertEqual(body["data"]["name"], "采购合同知识库")
self.assertEqual(self.audit_log_service.events[0]["action"], "create_knowledge_base")
self.assertEqual(
self.audit_log_service.events[0]["detail_json"],
{
"name": "采购合同知识库",
"description": "采购模板与制度",
"status": "active",
"document_count": 0,
},
)
def test_admin_can_upload_document(self):
app.dependency_overrides[require_current_user] = lambda: {
"id": "user-admin",
"tenant_id": "tenant-demo-001",
"role": "admin",
}
response = self.client.post(
"/api/v1/knowledge-bases/kb-123/documents",
data={"note": "首批规则"},
files={"file": ("rules.txt", "合同解除规则".encode("utf-8"), "text/plain")},
)
self.assertEqual(response.status_code, 200)
body = response.json()
self.assertEqual(body["data"]["file_name"], "rules.txt")
self.assertEqual(self.audit_log_service.events[0]["action"], "upload_knowledge_document")
self.assertEqual(
self.audit_log_service.events[0]["detail_json"],
{
"knowledge_base_id": "kb-123",
"file_name": "rules.txt",
"mime_type": "text/plain",
"file_size": len("合同解除规则".encode("utf-8")),
"status": "indexed",
"current_stage": "indexed",
"parse_status": "completed",
"index_status": "completed",
"error_message": None,
"note": "首批规则",
},
)
def test_member_cannot_access_knowledge_bases(self):
app.dependency_overrides[require_current_user] = lambda: {
"id": "user-member",
"tenant_id": "tenant-demo-001",
"role": "member",
}
response = self.client.get("/api/v1/knowledge-bases")
self.assertEqual(response.status_code, 403)
self.assertEqual(response.json()["message"], "forbidden")
self.assertEqual(self.audit_log_service.events, [])
if __name__ == "__main__":
unittest.main()