| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- from pathlib import Path
- from tests.conftest import (
- build_fastapi_test_client,
- build_postgres_database_url,
- build_postgres_engine,
- prepare_known_service_import,
- )
- def test_knowledge_service_post_contract_matches_frontend(
- tmp_path: Path,
- monkeypatch,
- ) -> None:
- prepare_known_service_import("knowledge-service")
- from app.bootstrap.app import create_app
- from app.db.models import Base
- from core_db import create_session_factory
- database_url = build_postgres_database_url(tmp_path, "knowledge-api")
- monkeypatch.setenv("AGENT_PLATFORM_DATABASE_URL", database_url)
- monkeypatch.setenv("AGENT_PLATFORM_OBJECT_STORAGE_BACKEND", "memory")
- engine = build_postgres_engine(database_url)
- Base.metadata.create_all(engine)
- app = create_app()
- app.state.session_factory = create_session_factory(engine)
- client = build_fastapi_test_client(app)
- storage_health_response = client.post("/knowledge/storage/health", json={})
- assert storage_health_response.status_code == 200
- assert storage_health_response.json()["data"]["backend"] == "memory"
- assert storage_health_response.json()["data"]["available"] is True
- base_response = client.post(
- "/knowledge/bases/create",
- json={
- "name": "Product Knowledge",
- "description": "Customer-facing docs",
- "metadata": {"owner": "support"},
- },
- )
- assert base_response.status_code == 200
- base_payload = base_response.json()["data"]
- assert base_payload["name"] == "Product Knowledge"
- assert "code" not in base_payload
- assert base_payload["createdTime"]
- list_bases_response = client.post(
- "/knowledge/bases/list",
- json={"page": 1, "pageSize": 20, "keyword": "Product"},
- )
- assert list_bases_response.status_code == 200
- assert list_bases_response.json()["data"]["total"] == 1
- archive_base_response = client.post(
- "/knowledge/bases/status",
- json={"knowledgeBaseId": base_payload["id"], "status": "archived"},
- )
- assert archive_base_response.status_code == 200
- assert archive_base_response.json()["data"]["status"] == "archived"
- restore_base_response = client.post(
- "/knowledge/bases/status",
- json={"knowledgeBaseId": base_payload["id"], "status": "active"},
- )
- assert restore_base_response.status_code == 200
- assert restore_base_response.json()["data"]["status"] == "active"
- document_response = client.post(
- "/knowledge/documents/create",
- json={
- "knowledgeBaseId": base_payload["id"],
- "title": "Invoice FAQ",
- "sourceType": "markdown",
- "contentText": "# Invoice FAQ\nCustomers can download invoices from Billing.",
- "chunkSize": 40,
- "chunkOverlap": 5,
- "asyncMode": False,
- "metadata": {"category": "billing"},
- },
- )
- assert document_response.status_code == 200
- document_payload = document_response.json()["data"]["document"]
- chunk_payloads = document_response.json()["data"]["chunks"]
- assert document_payload["knowledgeBaseId"] == base_payload["id"]
- assert document_payload["status"] == "indexed"
- assert document_payload["objectStorage"]["backend"] == "memory"
- assert chunk_payloads
- storage_status_response = client.post(
- "/knowledge/documents/storage/status",
- json={"documentId": document_payload["id"]},
- )
- assert storage_status_response.status_code == 200
- storage_status_payload = storage_status_response.json()["data"]
- assert storage_status_payload["exists"] is True
- assert storage_status_payload["sizeBytes"] > 0
- assert storage_status_payload["checkedTime"]
- content_response = client.post(
- "/knowledge/documents/content",
- json={
- "documentId": document_payload["id"],
- "includeText": True,
- "includeBase64": True,
- },
- )
- assert content_response.status_code == 200
- content_payload = content_response.json()["data"]
- assert content_payload["contentText"].startswith("# Invoice FAQ")
- assert content_payload["contentBase64"]
- reindex_response = client.post(
- "/knowledge/documents/reindex",
- json={
- "documentId": document_payload["id"],
- "chunkSize": 40,
- "chunkOverlap": 5,
- "asyncMode": False,
- },
- )
- assert reindex_response.status_code == 200
- assert reindex_response.json()["data"]["chunks"]
- chunks_response = client.post(
- "/knowledge/chunks/list",
- json={"page": 1, "pageSize": 20, "documentId": document_payload["id"]},
- )
- assert chunks_response.status_code == 200
- assert chunks_response.json()["data"]["total"] == len(chunk_payloads)
- search_response = client.post(
- "/knowledge/search/query",
- json={
- "knowledgeBaseId": base_payload["id"],
- "query": "download invoices",
- "topK": 3,
- "filters": {"status": "indexed"},
- },
- )
- assert search_response.status_code == 200
- search_payload = search_response.json()["data"]
- assert search_payload
- assert search_payload[0]["document"]["id"] == document_payload["id"]
- assert "scoreDetails" in search_payload[0]
- settings_response = client.post(
- "/knowledge/settings/update",
- json={
- "knowledgeBaseId": base_payload["id"],
- "retrievalMode": "hybrid",
- "embeddingModelId": "auto",
- "rerankModelId": "auto",
- "chunkSize": 600,
- "chunkOverlap": 80,
- "topK": 6,
- "minScore": 0.1,
- "maxCandidates": 40,
- "keywordWeight": 0.4,
- "vectorWeight": 0.45,
- "rerankWeight": 0.15,
- "queryRewrite": True,
- "requireCitations": True,
- },
- )
- assert settings_response.status_code == 200
- assert settings_response.json()["data"]["knowledgeBaseId"] == base_payload["id"]
- assert settings_response.json()["data"]["chunkSize"] == 600
- from app.infrastructure.object_storage import InMemoryObjectStorage
- InMemoryObjectStorage(bucket="agent-platform-knowledge").delete_object(
- object_key=document_payload["objectStorage"]["objectKey"])
- missing_storage_status_response = client.post(
- "/knowledge/documents/storage/status",
- json={"documentId": document_payload["id"]},
- )
- assert missing_storage_status_response.status_code == 200
- assert missing_storage_status_response.json()["data"]["exists"] is False
- missing_reindex_response = client.post(
- "/knowledge/documents/reindex",
- json={
- "documentId": document_payload["id"],
- "chunkSize": 40,
- "chunkOverlap": 5,
- "asyncMode": False,
- },
- )
- assert missing_reindex_response.status_code == 503
- document_detail_response = client.post(
- "/knowledge/documents/detail",
- json={"documentId": document_payload["id"]},
- )
- assert document_detail_response.status_code == 200
- assert document_detail_response.json()["data"]["status"] == "failed"
- delete_document_response = client.post(
- "/knowledge/documents/delete",
- json={"documentId": document_payload["id"]},
- )
- assert delete_document_response.status_code == 200
- assert delete_document_response.json()["data"]["deleted"] is True
- assert delete_document_response.json()["data"]["objectDeleted"] is False
- engine.dispose()
- Base.metadata.clear()
|