"""Smoke-tests every section-14 API operation through HTTP.""" import pytest from fastapi.testclient import TestClient @pytest.fixture(scope="module") def client(tmp_path_factory): from apps.api import create_app home = tmp_path_factory.mktemp("api_home") return TestClient(create_app(home=str(home))) def test_all_section14_operations(client): V = "/api/v1" assert client.get("/").status_code == 200 and "Mission board" in client.get("/").text assert client.get("/static/viewer.js").status_code == 200 # Project p = client.post(f"{V}/projects", json={"name": "api"}).json(); pid = p["project_id"] assert client.put(f"{V}/projects/{pid}/goal", json={"statement": "g"}).json()["goal"]["statement"] == "g" assert client.put(f"{V}/projects/{pid}/constraints", json={"allowed_elements": ["Cu"]}).json()["constraints"] # Candidate g = client.post(f"{V}/candidates/generate", json={"project_id": pid, "generator": "known_family", "params": {"kind": "fcc", "element": "Cu", "a": 3.6, "cubic": True}}).json() cid = g["candidate_id"] assert client.post(f"{V}/candidates/generate", json={"project_id": pid, "generator": "learned_model"}).json()["status"] == "NOT_SUPPORTED" t = client.post(f"{V}/candidates/{cid}/transform", json={"operation": "substitute", "params": {"index": 0, "new_symbol": "Ni"}}).json() assert t["parent_ids"] == [cid] assert client.post(f"{V}/candidates/validate_schema", json={"bad": 1}).json()["valid"] is False assert client.get(f"{V}/candidates/compare?a={cid}&b={t['candidate_id']}").json()["same_composition"] is False assert "Cu" in client.get(f"{V}/candidates/{cid}/export?fmt=xyz").text imp = client.post(f"{V}/candidates/import?project_id={pid}&fmt=xyz", content="2\n\nH 0 0 0\nH 0 0 0.74\n", headers={"content-type": "text/plain"}) assert imp.status_code == 200 and imp.json()["composition"] == {"H": 2} assert "unified" in client.get(f"{V}/candidates/{cid}").json() # Simulation assert any(s["solver_id"] == "ase_emt" and s["compatible"] for s in client.get(f"{V}/simulation/compatible?candidate_id={cid}&observable=energy").json()) assert client.get(f"{V}/simulation/estimate?candidate_id={cid}&solver_id=ase_emt&observable=energy").json()["compatible"] run = client.post(f"{V}/simulation/runs", json={"candidate_id": cid, "solver_id": "ase_emt", "observable": "energy"}).json() assert run["exit_status"] == "SUCCESS" assert client.get(f"{V}/simulation/jobs/{run['provenance']['job_id']}").json()["status"] == "done" arts = client.get(f"{V}/simulation/runs/{run['run_id']}/artifacts").json() assert arts and client.get(f"{V}/artifacts/{arts[0]['artifact_id']}").status_code == 200 assert len(client.get(f"{V}/simulation/solvers").json()) == 15 # Evidence # a single-point energy has no convergence test ('not_applicable') -> does not satisfy the M2 gate assert client.post(f"{V}/evidence/{cid}/maturity").json()["level"] == "M1" client.post(f"{V}/simulation/runs", json={"candidate_id": cid, "solver_id": "ase_emt", "observable": "lattice_constant"}) assert client.post(f"{V}/evidence/{cid}/maturity").json()["level"] == "M2" cl = client.post(f"{V}/evidence/{cid}/claims", json={"claim_text": "t"}).json(); assert cl["maturity_level"] == "M2" assert client.post(f"{V}/evidence/compare_sources", json=[{"source": "a", "value": 1.0, "unit": "eV"}, {"source": "b", "value": 1.1, "unit": "eV"}]).json()["comparable"] # Knowledge ev = client.post(f"{V}/knowledge/events", json={"subject": "s", "predicate": "p", "object": 1}).json(); assert ev["status"] == "proposed" assert client.post(f"{V}/knowledge/events/{ev['fact_id']}/verify").status_code == 400 assert client.get(f"{V}/knowledge/search?text={cid}").json()["facts"] assert client.get(f"{V}/knowledge/lineage/{t['candidate_id']}").json()["ancestors"] # Resource assert client.get(f"{V}/resources/capacity").json()["effective_concurrency"] >= 1 a = client.post(f"{V}/resources/allocate?job_id=probe&priority=validation", json={}).json(); assert a["granted"] client.post(f"{V}/resources/release?job_id=probe") assert client.post(f"{V}/resources/enforce_quota", json={"wall_time_s": 1e9}).status_code == 429 assert client.post(f"{V}/resources/checkpoint/{run['provenance']['job_id']}").json()["job_id"] assert client.get(f"{V}/resources/integrity").json()["bad_runs"] == [] # Mission + Agent m = client.post(f"{V}/missions", json={"project_id": pid, "research_question": "q", "autonomy_mode": "approval-required", "spec": {"track": "lj_cluster", "n_atoms": 7, "seed": 1, "n_random": 2, "evo_pop": 3, "evo_generations": 1, "n_select": 2}}).json() mid = m["mission_id"] assert len(client.post(f"{V}/missions/{mid}/plan").json()["tasks"]) == 13 assert client.post(f"{V}/missions/{mid}/run?background=false").json()["state"] == "awaiting_approval" client.post(f"{V}/missions/{mid}/approve") assert client.post(f"{V}/missions/{mid}/run?background=false").json()["state"] == "completed" assert client.post(f"{V}/missions/{mid}/pause").status_code == 200 assert client.post(f"{V}/missions/{mid}/resume").status_code == 400 # completed missions cannot resume br = client.post(f"{V}/missions/{mid}/branch", json={"research_question": "b"}).json(); assert br["parent_mission_id"] == mid assert client.post(f"{V}/missions/{br['mission_id']}/cancel").status_code == 400 assert client.post(f"{V}/missions/{br['mission_id']}/cancel?confirm=true").json()["state"] == "cancelled" assert len([r for r in client.get(f"{V}/agents").json() if not r["dynamic"]]) == 13 assert client.post(f"{V}/agents/messages", json={"sender": "a", "recipient": "coordinator", "body": {}, "mission_id": mid}).json()["recipient"] == "research_coordinator" assert client.get(f"{V}/agents/messages?mission_id={mid}").json() assert client.post(f"{V}/agents/publish_result?role=data_steward&mission_id={mid}", json={"x": 1}).json()["status"] == "proposed" assert client.post(f"{V}/agents/request_review?requester=a&reviewer=b&mission_id={mid}&question=q").status_code == 200 assert client.post(f"{V}/agents/assign_task?role=wrong&mission_id={mid}&stage=novelty").status_code == 400 assert all(b["passed"] for b in client.post(f"{V}/agents/benchmarks").json()) # Export assert client.get(f"{V}/export/structure/{cid}?fmt=cif").status_code == 200 assert client.get(f"{V}/export/run/{run['run_id']}").content[:2] == b"\x1f\x8b" assert client.get(f"{V}/export/report/{mid}").text.startswith("# MATTER OS evidence report") assert client.get(f"{V}/export/project/{pid}").content[:2] == b"\x1f\x8b" # dashboard data / viewer assert "maturity_counts" in client.get(f"{V}/dashboard/summary").json() v = client.get(f"{V}/viewer/{cid}?run_id={run['run_id']}").json() assert v["atoms"] and "disclaimer" in v["evidence_state"] assert client.get(f"{V}/observability/audit?limit=5").json() assert client.post(f"{V}/projects/{pid}/archive").status_code == 400 assert client.post(f"{V}/projects/{pid}/archive?confirm=true").json()["archived"]