124 lines
4.1 KiB
Python
124 lines
4.1 KiB
Python
"""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"]
|