Spaces:
Running
Running
File size: 9,990 Bytes
598a072 5194826 598a072 5194826 598a072 5194826 598a072 5194826 598a072 5194826 598a072 a326839 598a072 3e09cc5 598a072 5194826 598a072 a326839 3e09cc5 a326839 598a072 | 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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | """Tests for the admin maintenance routes that produce the REAL glass-box
receipts server-side (/api/admin/run-benchmarks, /api/admin/seed-commons) —
run in-Space, where the live ESM-2 model and Supabase credentials already
exist. Both are admin-token gated; both are exercised against the ACTUAL
bundled fixture (dee/data/dms_fixtures/) so a malformed manifest/CSV would
fail here too, not just in production.
"""
import json
import re
import types
from pathlib import Path
import pandas as pd
import pytest
from dee import server
from dee.core.dms_seed import parse_proteingym_csv
ADMIN_TOKEN = "test-admin-token-xyz"
@pytest.fixture
def client():
app = server.create_app()
app.config.update(TESTING=True)
return app.test_client()
def _with_admin(monkeypatch):
monkeypatch.setenv("TURINGDNA_ADMIN_TOKEN", ADMIN_TOKEN)
def _fixtures_dir():
return Path(server.__file__).resolve().parent / "data" / "dms_fixtures"
# --------------------------------------------------------------------------- #
# auth gate — shared shape for both routes
# --------------------------------------------------------------------------- #
def test_run_benchmarks_requires_admin_token(client, monkeypatch):
_with_admin(monkeypatch)
r = client.post("/api/admin/run-benchmarks")
assert r.status_code == 403
r2 = client.post("/api/admin/run-benchmarks", headers={"X-Admin-Token": "wrong"})
assert r2.status_code == 403
def test_seed_commons_requires_admin_token(client, monkeypatch):
_with_admin(monkeypatch)
r = client.post("/api/admin/seed-commons")
assert r.status_code == 403
# --------------------------------------------------------------------------- #
# /api/admin/run-benchmarks — real bundled fixture, fake (fast) scorer
# --------------------------------------------------------------------------- #
def test_run_benchmarks_against_real_fixture(client, monkeypatch, tmp_path):
_with_admin(monkeypatch)
real_fixtures = _fixtures_dir() # resolve BEFORE monkeypatching server.__file__ below
manifest = json.loads((real_fixtures / "manifest.json").read_text(encoding="utf-8"))
assert len(manifest) >= 3, "expected the 3 bundled + validated DMS assays"
# Build a per-sequence fake scorer covering EVERY bundled assay's own real
# labels (synthetic-but-distinct values, index-based) — a genuine smoke
# test of all 3 production fixtures end to end (real manifest -> real CSV
# -> predict_additive -> evaluate_dataset -> summarize -> written file),
# without needing ESM.
rx = re.compile(r"^([A-Za-z])(\d+)([A-Za-z*])$")
df_by_seq = {}
for a in manifest:
recs = parse_proteingym_csv((real_fixtures / a["csv"]).read_text(encoding="utf-8"))
assert len(recs) > 50, f"{a['name']} fixture looks too small to be real"
rows, seen = [], set()
for i, (lab, _v) in enumerate(recs):
m = rx.match(lab)
key = (int(m.group(2)) - 1, m.group(3).upper())
if key in seen:
continue
seen.add(key)
rows.append({"position": key[0], "wt_aa": m.group(1).upper(),
"mut_aa": key[1], "delta_ll": float(i % 37) * 0.1})
df_by_seq[a["sequence"]] = pd.DataFrame(rows)
monkeypatch.setattr(server._scoring, "get_scorer", lambda *a, **kw: "the-scorer")
monkeypatch.setattr(server._scoring, "score_guarded",
lambda scorer, seq: df_by_seq[seq])
# Write the output somewhere disposable so this test never touches the
# committed dee/data/benchmarks.json.
monkeypatch.setattr(server, "__file__",
str(tmp_path / "server.py")) # relocates Path(__file__).parent
(tmp_path / "data").mkdir()
import shutil
shutil.copytree(real_fixtures, tmp_path / "data" / "dms_fixtures")
r = client.post("/api/admin/run-benchmarks",
headers={"X-Admin-Token": ADMIN_TOKEN}, json={"model": "small"})
assert r.status_code == 200
body = r.get_json()
assert body["ok"] is True
assert body["model"] == "small"
assert body["generated_at"] is not None
assert body["summary"]["n_datasets"] == len(manifest)
names = {d["name"] for d in body["datasets"]}
assert names == {a["name"] for a in manifest}
for d in body["datasets"]:
assert d["n"] > 0
written = json.loads((tmp_path / "data" / "benchmarks.json").read_text(encoding="utf-8"))
assert written["summary"]["n_datasets"] == len(manifest)
def test_run_benchmarks_missing_fixtures_404(client, monkeypatch, tmp_path):
_with_admin(monkeypatch)
monkeypatch.setattr(server, "__file__", str(tmp_path / "server.py"))
(tmp_path / "data").mkdir() # no dms_fixtures subdir
r = client.post("/api/admin/run-benchmarks", headers={"X-Admin-Token": ADMIN_TOKEN})
assert r.status_code == 404
def test_run_benchmarks_surfaces_per_assay_failure(client, monkeypatch, tmp_path):
"""One assay's scoring blows up (e.g. a real ESM error on the Space) — the
other two must still complete, and the failure must be visible in the
response itself (name + error), not just swallowed into a shorter
'datasets' list with no explanation. This is what a real diagnosis of
'why did only 1 of 3 datasets come back' should read directly off the
curl output instead of requiring server-log access."""
_with_admin(monkeypatch)
real_fixtures = _fixtures_dir()
manifest = json.loads((real_fixtures / "manifest.json").read_text(encoding="utf-8"))
assert len(manifest) >= 3
def flaky_score_guarded(scorer, seq):
if len(seq) > 500: # the two longer real fixtures (PABP 577aa, DLG4 724aa)
raise RuntimeError("boom: simulated real scoring failure")
return pd.DataFrame([{"position": 0, "wt_aa": seq[0], "mut_aa": "Z", "delta_ll": 0.1}])
monkeypatch.setattr(server._scoring, "get_scorer", lambda *a, **kw: "the-scorer")
monkeypatch.setattr(server._scoring, "score_guarded", flaky_score_guarded)
monkeypatch.setattr(server, "__file__", str(tmp_path / "server.py"))
(tmp_path / "data").mkdir()
import shutil
shutil.copytree(real_fixtures, tmp_path / "data" / "dms_fixtures")
r = client.post("/api/admin/run-benchmarks",
headers={"X-Admin-Token": ADMIN_TOKEN}, json={"model": "small"})
assert r.status_code == 200
body = r.get_json()
long_assays = [a["name"] for a in manifest if len(a["sequence"]) > 500]
assert len(long_assays) == 2, "expected exactly PABP + DLG4 to be >500aa"
assert body["summary"]["n_datasets"] == len(manifest) - len(long_assays)
assert "failed" in body and len(body["failed"]) == len(long_assays)
failed_names = {f["name"] for f in body["failed"]}
assert failed_names == set(long_assays)
for f in body["failed"]:
assert "boom: simulated real scoring failure" in f["error"]
# --------------------------------------------------------------------------- #
# /api/admin/seed-commons — real bundled fixture, mocked Supabase write
# --------------------------------------------------------------------------- #
def test_seed_commons_against_real_fixture(client, monkeypatch):
_with_admin(monkeypatch)
captured = {}
def fake_replace(rows, source="user"):
captured["rows"] = rows
return {"ok": True}
monkeypatch.setattr(server._auth, "replace_mutation_priors", fake_replace)
r = client.post("/api/admin/seed-commons", headers={"X-Admin-Token": ADMIN_TOKEN})
assert r.status_code == 200
body = r.get_json()
assert body["ok"] is True
assert body["contributing_assays"] == 3
# 3 independent assays clears the k-anonymity floor (MIN_USERS=3): every
# single-mutant scan covers close to all 19 substitutions at every
# position, so most of the 380 possible substitution TYPES show up in
# all three proteins' data and survive. Proves the privacy floor is
# exactly a floor, not a permanent block, once there's real independent
# coverage — and that it produces real, usable rows on real data.
assert body["substitutions"] > 0
assert len(captured["rows"]) == body["substitutions"]
for row in captured["rows"]:
assert row["n_users"] >= 3 # every kept row backed by all 3 independent assays
assert ">" in row["substitution"]
def test_seed_commons_survives_one_bad_csv(client, monkeypatch, tmp_path):
"""A single unreadable/corrupt fixture CSV must not 500 the whole request
(there was previously no try/except around this loop at all) — it should
degrade to the other assays and report the failure by name."""
_with_admin(monkeypatch)
real_fixtures = _fixtures_dir()
monkeypatch.setattr(server._auth, "replace_mutation_priors", lambda rows, source="user": {"ok": True})
monkeypatch.setattr(server, "__file__", str(tmp_path / "server.py"))
(tmp_path / "data").mkdir()
import shutil
dest = tmp_path / "data" / "dms_fixtures"
shutil.copytree(real_fixtures, dest)
manifest = json.loads((dest / "manifest.json").read_text(encoding="utf-8"))
broken_name = manifest[0]["name"]
(dest / manifest[0]["csv"]).unlink() # simulate a missing/corrupt fixture file
r = client.post("/api/admin/seed-commons", headers={"X-Admin-Token": ADMIN_TOKEN})
assert r.status_code == 200
body = r.get_json()
assert body["contributing_assays"] == len(manifest) - 1
assert "failed" in body and len(body["failed"]) == 1
assert body["failed"][0]["name"] == broken_name
def test_seed_commons_gated_before_effective_date(client, monkeypatch):
_with_admin(monkeypatch)
import datetime as _dt
from dee.core import aggregate as _agg
monkeypatch.setattr(_agg, "EFFECTIVE_DATE", _dt.date(2099, 1, 1))
r = client.post("/api/admin/seed-commons", headers={"X-Admin-Token": ADMIN_TOKEN})
assert r.status_code == 423
assert r.get_json()["error"] == "gated"
|