Files
GEWU/tests/api/test_health.py
T
vasily 78033bb830
CI / quality (push) Canceled after 0s
feat: online verification, node removals, and knowledge browser
Adds claim-bound online evidence records and citation verification scripts,
node removal transport/adapter, retrieval benchmark and owner-review tooling,
GraphCanvas/SourceDetail knowledge browser UI, and the ingest handoff helper.
Bumps the agents/gewu pack to the online-verification branch.
2026-10-16 20:02:29 +08:00

94 lines
3.4 KiB
Python

import asyncio
from pathlib import Path
import httpx
import pytest
from _pytest.monkeypatch import MonkeyPatch
from fastapi.routing import APIRoute
from gewu.bootstrap.app import create_app, create_local_app
def test_health_is_available_without_exposing_mutation_routes() -> None:
async def request_health() -> httpx.Response:
async with httpx.AsyncClient(
transport=httpx.ASGITransport(app=create_app()),
base_url="http://gewu.test",
) as client:
return await client.get("/health")
response = asyncio.run(request_health())
assert response.status_code == 200
assert response.json() == {"status": "ok", "service": "gewu"}
routes = {
f"{method} {route.path}"
for route in create_app().routes
if isinstance(route, APIRoute)
for method in route.methods or ()
}
assert routes == {"GET /health"}
def test_local_factory_composes_private_persistent_read_service(
monkeypatch: MonkeyPatch, tmp_path: Path
) -> None:
data_root = tmp_path / "private-gewu"
monkeypatch.setenv("GEWU_DATA_ROOT", str(data_root))
app = create_local_app()
route_paths = {route.path for route in app.routes if isinstance(route, APIRoute)}
assert route_paths == {
"/health",
"/v1/diagnostics",
"/v1/admin/projects",
"/v1/admin/projects/{project_id}",
"/v1/admin/credentials",
"/v1/admin/credentials/{credential_id}",
"/v1/admin/events",
"/v1/admin/users",
"/v1/admin/users/{username}",
"/v1/users/session",
"/v1/me",
"/v1/me/password",
"/v1/me/agent-credentials",
"/v1/me/agent-credentials/{credential_id}",
"/v1/admin/projects/{project_id}/archive",
"/v1/projects/{project_id}/nodes/{node_id}",
"/v1/projects/{project_id}/nodes/{node_id}/history",
"/v1/projects/{project_id}/sources/{revision_id}",
"/v1/projects/{project_id}/sources/{revision_id}/artifact",
"/v1/projects/{project_id}/sources/{revision_id}/extractions/{extraction_id}/blocks/{block_id}",
"/v1/projects/{project_id}/sources/{revision_id}/nodes",
"/v1/neighbors",
"/v1/projects",
"/v1/search",
"/v1/knowledge/browse",
"/v1/knowledge/graph",
"/v1/sources",
"/v1/session",
"/auth/owner-session",
"/v1/ingest-reviews",
"/v1/ingest-reviews/{review_id}/decision",
"/v1/projects/{project_id}/node-removals",
"/v1/projects/{project_id}/nodes/{node_id}/removal",
"/v1/projects/{project_id}/nodes/{node_id}/restore-removal",
}
assert (data_root / "knowledge.git" / "HEAD").is_file()
assert (data_root / "identity.sqlite3").is_file()
assert (data_root / "search.sqlite3").is_file()
assert (data_root / "node-removals.sqlite3").is_file()
assert (data_root / "node-removals.sqlite3").stat().st_mode & 0o077 == 0
assert (data_root / "search.sqlite3").stat().st_mode & 0o077 == 0
assert (data_root.stat().st_mode & 0o777) == 0o700
def test_local_factory_rejects_symlinked_data_root(
monkeypatch: MonkeyPatch, tmp_path: Path
) -> None:
target = tmp_path / "real-root"
target.mkdir()
link = tmp_path / "linked-root"
link.symlink_to(target, target_is_directory=True)
monkeypatch.setenv("GEWU_DATA_ROOT", str(link))
with pytest.raises(ValueError, match="symbolic links"):
create_local_app()