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