"""test_api.py —— FastAPI 端点(TestClient + 假 embed,不碰真 ollama)。""" from __future__ import annotations import pytest from starlette.testclient import TestClient from vstore import vault as vault_mod from vstore.api import app from vstore.settings import VstorePaths, set_paths @pytest.fixture def client(tmp_path, embed_fn): set_paths(VstorePaths(root=str(tmp_path))) with TestClient(app) as c: yield c def test_health(client): resp = client.get("/api/vstore/health") assert resp.status_code == 200 data = resp.json() assert data["ok"] is True assert data["count"] == 0 def test_ingest_then_search(client): resp = client.post( "/api/vstore/ingest", files={"file": ("report.txt", "小麦育种年度报告内容。".encode("utf-8"), "text/plain")}, data={"name": "年度报告", "category": "农业", "description": "小麦"}, ) assert resp.status_code == 200 data = resp.json() assert data["ok"] is True item = data["item"] assert item["document_id"] assert item["name"] == "年度报告" resp2 = client.get("/api/vstore/search", params={"q": "小麦"}) assert resp2.status_code == 200 data2 = resp2.json() assert data2["ok"] is True assert len(data2["items"]) >= 1 assert data2["items"][0]["id"] == item["document_id"] def test_ingest_empty_file_rejected(client): resp = client.post( "/api/vstore/ingest", files={"file": ("a.txt", b"", "text/plain")}, data={"name": "x"}, ) assert resp.status_code == 422 data = resp.json() assert data["ok"] is False assert data["error"]["code"] == "VALIDATION" def test_document_roundtrip(client): doc_id = client.post( "/api/vstore/ingest", files={"file": ("d.txt", "文档正文内容。".encode("utf-8"))}, data={"name": "d"}, ).json()["item"]["document_id"] resp = client.get(f"/api/vstore/documents/{doc_id}") assert resp.status_code == 200 doc = resp.json()["document"] assert "文档正文内容" in doc["paragraphs"][0] # style(非 docx → 空 hints) resp_style = client.get(f"/api/vstore/documents/{doc_id}/style") assert resp_style.status_code == 200 assert resp_style.json()["style_hints"] == {} def test_document_404(client): assert client.get("/api/vstore/documents/nope").status_code == 404 assert client.get("/api/vstore/documents/nope/style").status_code == 404 def test_delete_document(client): doc_id = client.post( "/api/vstore/ingest", files={"file": ("d.txt", b"content")}, data={"name": "d"}, ).json()["item"]["document_id"] resp = client.delete(f"/api/vstore/documents/{doc_id}") assert resp.json() == {"ok": True, "removed": True} assert client.get(f"/api/vstore/documents/{doc_id}").status_code == 404 def test_rebuild_index(client): client.post( "/api/vstore/ingest", files={"file": ("a.txt", b"aaa")}, data={"name": "a"}, ) resp = client.post("/api/vstore/rebuild-index") assert resp.status_code == 200 data = resp.json() assert data["ok"] is True assert data["count"] == 1 def test_search_params_bounded(client): resp = client.get("/api/vstore/search", params={"q": "", "top_k": 999}) assert resp.status_code == 200 assert resp.json()["ok"] is True