File size: 4,314 Bytes
ff453a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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