"""Phase 2 review queue API tests.""" from __future__ import annotations import importlib from collections.abc import Generator from contextlib import asynccontextmanager from fastapi.testclient import TestClient from ont_platform.api import db_deps from ont_platform.storage.models import Base from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.pool import StaticPool main_module = importlib.import_module("ont_platform.api.main") @asynccontextmanager async def _noop_lifespan(app): yield def _phase2_client(monkeypatch) -> TestClient: monkeypatch.setenv("PHASE", "2") engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) session_factory = sessionmaker(bind=engine) def override_get_db() -> Generator[Session, None, None]: db = session_factory() try: yield db finally: db.close() app = main_module.create_app() app.router.lifespan_context = _noop_lifespan app.dependency_overrides[db_deps.get_db] = override_get_db return TestClient(app, raise_server_exceptions=True, backend="asyncio") def test_review_api_ingests_approves_and_promotes_candidate(monkeypatch) -> None: with _phase2_client(monkeypatch) as client: ingest = client.post( "/api/v1/review/ingest/lightweight", json={ "project_id": "proj_api", "document_id": "doc_api", "entities": [ { "id": "E_api", "label": "Acme", "type": "org", "confidence": 0.93, "evidence_ids": ["EV_api"], } ], "relations": [], "evidence_spans": [ { "id": "EV_api", "text": "Acme is mentioned in the source.", "start_offset": 0, "end_offset": 32, } ], "source_trust": 0.9, "validation_passed": True, }, ) approve = client.post( "/api/v1/review/candidates/entity/E_api/approve", json={"reviewed_by": "lasta", "reason": "verified"}, ) promote = client.post("/api/v1/review/promote", params={"project_id": "proj_api"}) assert ingest.status_code == 200, ingest.text assert ingest.json()["source_type"] == "lightweight" assert approve.status_code == 200, approve.text assert approve.json()["decision"]["new_status"] == "approved" assert promote.status_code == 200, promote.text plan = promote.json()["promotion_plan"] assert plan["entity_count"] == 1 assert plan["blocked_count"] == 0 assert plan["entities"][0]["id"] == "E_api" def test_review_api_blocks_approval_without_evidence(monkeypatch) -> None: with _phase2_client(monkeypatch) as client: ingest = client.post( "/api/v1/review/ingest/ontocast", json={ "project_id": "proj_api", "document_id": "doc_api", "entities": [ { "id": "E_no_evidence_api", "label": "Unsupported", "entity_type": "concept", "confidence": 0.99, "evidence_ids": [], } ], "relations": [], "evidence_spans": [], "source_trust": 0.95, "validation_passed": True, }, ) approve = client.post( "/api/v1/review/candidates/entity/E_no_evidence_api/approve", json={"reviewed_by": "lasta"}, ) assert ingest.status_code == 200, ingest.text assert ingest.json()["source_type"] == "ontocast" assert approve.status_code == 422 assert "without valid evidence" in approve.json()["detail"]