Skip to content

Commit c6281b5

Browse files
committed
Add report rerun route coverage
1 parent f10ecb1 commit c6281b5

2 files changed

Lines changed: 317 additions & 18 deletions

File tree

tests/unit/services/test_report_spec_service.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ def test_raises_for_mixed_population_types(self, test_db):
9090
population_type="geography",
9191
policy_id=2,
9292
)
93-
report_output = report_output_service.create_report_output(
94-
country_id="us",
95-
simulation_1_id=simulation_1["id"],
96-
simulation_2_id=simulation_2["id"],
97-
year="2025",
98-
)
93+
report_output = {
94+
"country_id": "us",
95+
"simulation_1_id": simulation_1["id"],
96+
"simulation_2_id": simulation_2["id"],
97+
"year": "2025",
98+
}
9999

100100
with pytest.raises(ValueError) as exc_info:
101101
report_spec_service.build_report_spec(
@@ -117,12 +117,12 @@ def test_raises_for_mismatched_household_ids(self, test_db):
117117
population_type="household",
118118
policy_id=2,
119119
)
120-
report_output = report_output_service.create_report_output(
121-
country_id="us",
122-
simulation_1_id=simulation_1["id"],
123-
simulation_2_id=simulation_2["id"],
124-
year="2025",
125-
)
120+
report_output = {
121+
"country_id": "us",
122+
"simulation_1_id": simulation_1["id"],
123+
"simulation_2_id": simulation_2["id"],
124+
"year": "2025",
125+
}
126126

127127
with pytest.raises(ValueError) as exc_info:
128128
report_spec_service.build_report_spec(
@@ -144,12 +144,12 @@ def test_raises_for_mismatched_geography_ids(self, test_db):
144144
population_type="geography",
145145
policy_id=11,
146146
)
147-
report_output = report_output_service.create_report_output(
148-
country_id="us",
149-
simulation_1_id=simulation_1["id"],
150-
simulation_2_id=simulation_2["id"],
151-
year="2027",
152-
)
147+
report_output = {
148+
"country_id": "us",
149+
"simulation_1_id": simulation_1["id"],
150+
"simulation_2_id": simulation_2["id"],
151+
"year": "2027",
152+
}
153153

154154
with pytest.raises(ValueError) as exc_info:
155155
report_spec_service.build_report_spec(

tests/unit/test_stage5_routes.py

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,137 @@ def test_patch_report_output_explicit_run_id_updates_only_that_run(test_db):
11141114
assert rerun_after["output"] == json.dumps({"result": "explicit rerun"})
11151115

11161116

1117+
def test_patch_report_output_explicit_run_id_through_legacy_id_updates_canonical_run(
1118+
test_db,
1119+
):
1120+
simulation = simulation_service.create_simulation(
1121+
country_id="us",
1122+
population_id="household_route_legacy_explicit_report_run",
1123+
population_type="household",
1124+
policy_id=79,
1125+
)
1126+
canonical_report = report_output_service.create_report_output(
1127+
country_id="us",
1128+
simulation_1_id=simulation["id"],
1129+
simulation_2_id=None,
1130+
year="2026",
1131+
)
1132+
report_output_service.update_report_output(
1133+
country_id="us",
1134+
report_id=canonical_report["id"],
1135+
status="complete",
1136+
output=json.dumps({"result": "initial"}),
1137+
)
1138+
initial_run = test_db.query(
1139+
"SELECT * FROM report_output_runs WHERE report_output_id = ?",
1140+
(canonical_report["id"],),
1141+
).fetchone()
1142+
rerun = report_run_service.create_report_output_run(
1143+
canonical_report["id"], trigger_type="rerun"
1144+
)
1145+
test_db.query(
1146+
"""
1147+
INSERT INTO report_outputs (
1148+
id, country_id, simulation_1_id, simulation_2_id, api_version, status, year,
1149+
report_identity_hash, report_identity_schema_version
1150+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1151+
""",
1152+
(
1153+
3002,
1154+
"us",
1155+
simulation["id"],
1156+
None,
1157+
"legacy-report-cache-version",
1158+
"complete",
1159+
"2026",
1160+
canonical_report["report_identity_hash"],
1161+
canonical_report["report_identity_schema_version"],
1162+
),
1163+
)
1164+
report_output_id_map_service.set_mapping(
1165+
legacy_report_output_id=3002,
1166+
canonical_report_output_id=canonical_report["id"],
1167+
)
1168+
1169+
client = create_test_client()
1170+
response = client.patch(
1171+
"/us/report",
1172+
json={
1173+
"id": 3002,
1174+
"report_output_run_id": rerun["id"],
1175+
"status": "complete",
1176+
"output": json.dumps({"result": "legacy explicit rerun"}),
1177+
},
1178+
)
1179+
1180+
assert response.status_code == 200
1181+
payload = response.get_json()
1182+
assert payload["result"]["id"] == 3002
1183+
1184+
initial_run_after = test_db.query(
1185+
"SELECT * FROM report_output_runs WHERE id = ?",
1186+
(initial_run["id"],),
1187+
).fetchone()
1188+
rerun_after = test_db.query(
1189+
"SELECT * FROM report_output_runs WHERE id = ?",
1190+
(rerun["id"],),
1191+
).fetchone()
1192+
assert initial_run_after["output"] == json.dumps({"result": "initial"})
1193+
assert rerun_after["report_output_id"] == canonical_report["id"]
1194+
assert rerun_after["output"] == json.dumps({"result": "legacy explicit rerun"})
1195+
1196+
1197+
def test_create_report_rerun_via_canonical_id_creates_canonical_linked_runs(test_db):
1198+
simulation = simulation_service.create_simulation(
1199+
country_id="us",
1200+
population_id="household_route_canonical_rerun",
1201+
population_type="household",
1202+
policy_id=80,
1203+
)
1204+
canonical_report = report_output_service.create_report_output(
1205+
country_id="us",
1206+
simulation_1_id=simulation["id"],
1207+
simulation_2_id=None,
1208+
year="2026",
1209+
)
1210+
report_output_service.update_report_output(
1211+
country_id="us",
1212+
report_id=canonical_report["id"],
1213+
status="complete",
1214+
output=json.dumps({"result": "canonical"}),
1215+
)
1216+
1217+
client = create_test_client()
1218+
response = client.post(f"/us/report/{canonical_report['id']}/rerun", json={})
1219+
1220+
assert response.status_code == 201
1221+
result = response.get_json()["result"]
1222+
assert result["requested_report_output_id"] == canonical_report["id"]
1223+
assert result["report_output_id"] == canonical_report["id"]
1224+
assert len(result["simulation_run_ids"]) == 1
1225+
1226+
report_runs = test_db.query(
1227+
"""
1228+
SELECT * FROM report_output_runs
1229+
WHERE report_output_id = ?
1230+
ORDER BY run_sequence
1231+
""",
1232+
(canonical_report["id"],),
1233+
).fetchall()
1234+
assert len(report_runs) == 2
1235+
assert report_runs[0]["trigger_type"] == "initial"
1236+
assert report_runs[1]["id"] == result["report_output_run_id"]
1237+
assert report_runs[1]["trigger_type"] == "rerun"
1238+
assert report_runs[1]["status"] == "pending"
1239+
1240+
simulation_run = test_db.query(
1241+
"SELECT * FROM simulation_runs WHERE id = ?",
1242+
(result["simulation_run_ids"][0],),
1243+
).fetchone()
1244+
assert simulation_run["report_output_run_id"] == result["report_output_run_id"]
1245+
assert simulation_run["input_position"] == 1
1246+
1247+
11171248
def test_create_report_rerun_via_legacy_id_creates_canonical_linked_runs(test_db):
11181249
simulation = simulation_service.create_simulation(
11191250
country_id="us",
@@ -1181,6 +1312,174 @@ def test_create_report_rerun_via_legacy_id_creates_canonical_linked_runs(test_db
11811312
assert simulation_run["input_position"] == 1
11821313

11831314

1315+
def test_create_report_rerun_for_comparison_report_creates_two_linked_simulation_runs(
1316+
test_db,
1317+
):
1318+
baseline_simulation = simulation_service.create_simulation(
1319+
country_id="us",
1320+
population_id="state/nc",
1321+
population_type="geography",
1322+
policy_id=81,
1323+
)
1324+
reform_simulation = simulation_service.create_simulation(
1325+
country_id="us",
1326+
population_id="state/nc",
1327+
population_type="geography",
1328+
policy_id=82,
1329+
)
1330+
report = report_output_service.create_report_output(
1331+
country_id="us",
1332+
simulation_1_id=baseline_simulation["id"],
1333+
simulation_2_id=reform_simulation["id"],
1334+
year="2026",
1335+
)
1336+
report_output_service.update_report_output(
1337+
country_id="us",
1338+
report_id=report["id"],
1339+
status="complete",
1340+
output=json.dumps({"result": "comparison"}),
1341+
)
1342+
1343+
client = create_test_client()
1344+
response = client.post(f"/us/report/{report['id']}/rerun", json={})
1345+
1346+
assert response.status_code == 201
1347+
result = response.get_json()["result"]
1348+
assert result["report_output_id"] == report["id"]
1349+
assert len(result["simulation_run_ids"]) == 2
1350+
1351+
linked_simulation_runs = test_db.query(
1352+
"""
1353+
SELECT * FROM simulation_runs
1354+
WHERE report_output_run_id = ?
1355+
ORDER BY input_position
1356+
""",
1357+
(result["report_output_run_id"],),
1358+
).fetchall()
1359+
assert [run["simulation_id"] for run in linked_simulation_runs] == [
1360+
baseline_simulation["id"],
1361+
reform_simulation["id"],
1362+
]
1363+
assert [run["input_position"] for run in linked_simulation_runs] == [1, 2]
1364+
assert [run["status"] for run in linked_simulation_runs] == [
1365+
"pending",
1366+
"pending",
1367+
]
1368+
1369+
1370+
def test_create_report_rerun_rejects_report_with_missing_linked_simulation(test_db):
1371+
test_db.query(
1372+
"""
1373+
INSERT INTO report_outputs (
1374+
country_id, simulation_1_id, simulation_2_id, api_version, status, year
1375+
) VALUES (?, ?, ?, ?, ?, ?)
1376+
""",
1377+
("us", 987654, None, get_report_output_cache_version("us"), "complete", "2026"),
1378+
)
1379+
report = test_db.query(
1380+
"SELECT * FROM report_outputs ORDER BY id DESC LIMIT 1"
1381+
).fetchone()
1382+
1383+
client = create_test_client()
1384+
response = client.post(f"/us/report/{report['id']}/rerun", json={})
1385+
1386+
assert response.status_code == 400
1387+
assert "Simulation #987654 not found" in response.get_data(as_text=True)
1388+
1389+
report_runs = test_db.query(
1390+
"SELECT * FROM report_output_runs WHERE report_output_id = ?",
1391+
(report["id"],),
1392+
).fetchall()
1393+
assert report_runs == []
1394+
1395+
1396+
def test_report_rerun_http_lifecycle_patches_linked_runs_and_reads_display(
1397+
test_db,
1398+
):
1399+
client = create_test_client()
1400+
simulation_response = client.post(
1401+
"/us/simulation",
1402+
json={
1403+
"population_id": "household_route_http_lifecycle",
1404+
"population_type": "household",
1405+
"policy_id": 83,
1406+
},
1407+
)
1408+
assert simulation_response.status_code == 201
1409+
simulation = simulation_response.get_json()["result"]
1410+
1411+
report_response = client.post(
1412+
"/us/report",
1413+
json={
1414+
"simulation_1_id": simulation["id"],
1415+
"simulation_2_id": None,
1416+
"year": "2026",
1417+
},
1418+
)
1419+
assert report_response.status_code == 201
1420+
report = report_response.get_json()["result"]
1421+
1422+
initial_patch_response = client.patch(
1423+
"/us/report",
1424+
json={
1425+
"id": report["id"],
1426+
"status": "complete",
1427+
"output": json.dumps({"result": "initial report"}),
1428+
},
1429+
)
1430+
assert initial_patch_response.status_code == 200
1431+
1432+
rerun_response = client.post(f"/us/report/{report['id']}/rerun", json={})
1433+
assert rerun_response.status_code == 201
1434+
rerun = rerun_response.get_json()["result"]
1435+
assert len(rerun["simulation_run_ids"]) == 1
1436+
1437+
simulation_patch_response = client.patch(
1438+
"/us/simulation",
1439+
json={
1440+
"id": simulation["id"],
1441+
"simulation_run_id": rerun["simulation_run_ids"][0],
1442+
"status": "complete",
1443+
"output": json.dumps({"result": "rerun simulation"}),
1444+
},
1445+
)
1446+
assert simulation_patch_response.status_code == 200
1447+
1448+
report_patch_response = client.patch(
1449+
"/us/report",
1450+
json={
1451+
"id": report["id"],
1452+
"report_output_run_id": rerun["report_output_run_id"],
1453+
"status": "complete",
1454+
"output": json.dumps({"result": "rerun report"}),
1455+
},
1456+
)
1457+
assert report_patch_response.status_code == 200
1458+
1459+
get_response = client.get(f"/us/report/{report['id']}")
1460+
assert get_response.status_code == 200
1461+
result = get_response.get_json()["result"]
1462+
assert result["id"] == report["id"]
1463+
assert result["status"] == "complete"
1464+
assert result["output"] == json.dumps({"result": "rerun report"})
1465+
1466+
report_rows = test_db.query("SELECT * FROM report_outputs").fetchall()
1467+
report_runs = test_db.query(
1468+
"SELECT * FROM report_output_runs WHERE report_output_id = ?",
1469+
(report["id"],),
1470+
).fetchall()
1471+
linked_simulation_runs = test_db.query(
1472+
"""
1473+
SELECT * FROM simulation_runs
1474+
WHERE report_output_run_id = ?
1475+
""",
1476+
(rerun["report_output_run_id"],),
1477+
).fetchall()
1478+
assert len(report_rows) == 1
1479+
assert len(report_runs) == 2
1480+
assert len(linked_simulation_runs) == 1
1481+
1482+
11841483
def test_patch_report_output_persists_run_metadata_fields(test_db):
11851484
simulation = simulation_service.create_simulation(
11861485
country_id="us",

0 commit comments

Comments
 (0)