shrut27's picture
Implement complete API contract, persistence, jobs, artifacts, and architecture status
ff453a6 verified
Raw
History Blame Contribute Delete
4.31 kB
from pathlib import Path
from fastapi.testclient import TestClient
from api import store
from api.main import app
def wait_result(client, job_id):
job = client.get(f"/jobs/{job_id}").json()
assert job["status"] == "succeeded", job
return job["output"]
def test_complete_endpoint_contract(tmp_path: Path):
store.DB_PATH = tmp_path / "test.db"
store.init_db()
with TestClient(app) as client:
assert client.get("/health").status_code == 200
project = client.post(
"/projects",
json={"name": "Y220C benchmark", "cancer_type": "Lung Cancer"},
).json()
pid = project["project_id"]
ingest = client.post(
"/variants:ingest",
json={
"project_id": pid,
"records": [{
"Site": "Exon 6", "Variant": "TP53:p.Y220C",
"Allele Frequency": 0.01, "Type": "Missense",
"Effect": "Loss-of-function",
}],
},
)
assert ingest.status_code == 202
ingest_out = wait_result(client, ingest.json()["job_id"])
variant_id = ingest_out["variant_ids"][0]
analyze = client.post(
f"/variants/{variant_id}/analyze", json={"project_id": pid}
)
analyzed = wait_result(client, analyze.json()["job_id"])
assert analyzed["hgvs_p"] == "p.Y220C"
assert "Docking + MD" in analyzed["route"]
prep = client.post(
"/structures:prepare",
json={"project_id": pid, "variant_ids": [variant_id]},
)
prep_out = wait_result(client, prep.json()["job_id"])
structure_id = prep_out["structure_ids"][0]
assert prep_out["structures"][0]["ddg_kcal"] == 3.78
pocket = client.post(
"/pockets:detect",
json={"project_id": pid, "structure_ids": [structure_id]},
)
pocket_out = wait_result(client, pocket.json()["job_id"])
assert pocket_out["pockets"][0]["mutant_created"] is True
screen = client.post(
"/compounds:screen",
json={"project_id": pid, "variant_id": variant_id, "limit": 10},
)
screen_out = wait_result(client, screen.json()["job_id"])
assert len(screen_out["candidates"]) == 10
compounds = [{
"compound_id": "CMP-1", "name": "Candidate 1",
"mw": 330, "logp": 2.5, "tpsa": 70, "rotbonds": 4,
}]
dock = client.post(
"/docking:run",
json={"project_id": pid, "variant_id": variant_id, "compounds": compounds},
)
dock_out = wait_result(client, dock.json()["job_id"])
pose = dock_out["poses"][0]
assert pose["units"] == "kcal/mol"
md = client.post(
"/md:run",
json={
"project_id": pid,
"complexes": [{
"complex_id": pose["docking_id"], "dock_mut": pose["dock_mut"],
"mutant_preference": pose["mutant_preference"], "rotbonds": 4,
}],
},
)
md_out = wait_result(client, md.json()["job_id"])
assert md_out["results"][0]["replicas"] == 3
candidate = {
"variant": variant_id, "name": "Candidate 1",
"Bmut": 0.8, "Sselectivity": 0.7, "MDstability": 0.75,
"Frescue": 0.8, "ADMET": 0.7, "Evidence": 0.6, "Risk": 0.2,
"confidence": 0.8, "admet_flag": "Acceptable",
}
ranking = client.post(
"/rankings:compute",
json={"project_id": pid, "variant_id": variant_id, "candidates": [candidate]},
)
rank_out = wait_result(client, ranking.json()["job_id"])
assert rank_out["shortlist"][0]["rank"] == 1
report = client.get(f"/projects/{pid}/report")
assert report.status_code == 200
body = report.json()
assert body["summary"]["variants"] == 1
assert body["summary"]["ranked_candidates"] == 1
assert len(client.get(f"/projects/{pid}/jobs").json()) == 8
assert len(client.get(f"/projects/{pid}/artifacts").json()) >= 6
artifact_id = body["artifacts"][0]["artifact_id"]
assert client.get(f"/artifacts/{artifact_id}").status_code == 200