|
| 1 | +"""Integration test: full platform/acquisition_type lifecycle against the production server. |
| 2 | +
|
| 3 | +Steps |
| 4 | +----- |
| 5 | +1. POST /acquisition-types — register (platform="test", acquisition_type=<unique>) |
| 6 | +2. POST /acquisition-types — re-post the same pair → still 200, dedupes (idempotent) |
| 7 | +3. GET /acquisition-types — verify the pair is present |
| 8 | +4. POST /scheduled-acquisitions with an unregistered acquisition_type → expect 400 |
| 9 | +5. POST /scheduled-acquisitions with a missing field → expect 422 (typed body) |
| 10 | +6. POST /scheduled-acquisitions, date=today, our acquisition_type → 200, get uuid |
| 11 | +7. GET /scheduled-acquisitions/{uuid} — verify subject_id, date, platform="test", acquisition_type |
| 12 | +8. GET /scheduled-acquisitions/{made-up-uuid} → expect 404 |
| 13 | +9. GET /scheduled-acquisitions (default, future-only) — today's uuid is present |
| 14 | +10. POST /scheduled-acquisitions, date=yesterday (past) — second uuid |
| 15 | +11. GET /scheduled-acquisitions (default, future-only) — past uuid is excluded |
| 16 | +12. GET /scheduled-acquisitions?include_past=true — both uuids present |
| 17 | +
|
| 18 | +Usage |
| 19 | +----- |
| 20 | + python scripts/test_acquisitions_integration.py |
| 21 | +""" |
| 22 | + |
| 23 | +import sys |
| 24 | +import time |
| 25 | +from datetime import date, timedelta |
| 26 | + |
| 27 | +import requests |
| 28 | + |
| 29 | +BASE_URL = "https://metadata-portal.allenneuraldynamics.org" |
| 30 | +PLATFORM = "test" |
| 31 | +ACQUISITION_TYPE = f"integration-test-type-{int(time.time())}" |
| 32 | +SUBJECT_ID = f"integration-test-subject-{int(time.time())}" |
| 33 | + |
| 34 | +ACQUISITION_TYPES_URL = f"{BASE_URL}/acquisition-types" |
| 35 | +SCHEDULED_ACQUISITIONS_URL = f"{BASE_URL}/scheduled-acquisitions" |
| 36 | + |
| 37 | +print(f"Testing against: {BASE_URL}") |
| 38 | +print(f"platform={PLATFORM!r} acquisition_type={ACQUISITION_TYPE!r}") |
| 39 | +print("=" * 60) |
| 40 | + |
| 41 | + |
| 42 | +def sep(title): |
| 43 | + print(f"\n{'─' * 60}") |
| 44 | + print(f" {title}") |
| 45 | + print(f"{'─' * 60}") |
| 46 | + |
| 47 | + |
| 48 | +def check(response, expected_status): |
| 49 | + if response.status_code != expected_status: |
| 50 | + print(f" FAIL status={response.status_code} body={response.text[:400]}") |
| 51 | + sys.exit(1) |
| 52 | + print(f" OK status={response.status_code}") |
| 53 | + try: |
| 54 | + return response.json() |
| 55 | + except Exception: |
| 56 | + return {} |
| 57 | + |
| 58 | + |
| 59 | +# --------------------------------------------------------------------------- |
| 60 | +# Step 1: POST /acquisition-types — register platform="test" + acquisition_type |
| 61 | +# --------------------------------------------------------------------------- |
| 62 | + |
| 63 | +sep("Step 1: POST /acquisition-types (register platform:test pair)") |
| 64 | +r = requests.post(ACQUISITION_TYPES_URL, json={"platform": PLATFORM, "acquisition_type": ACQUISITION_TYPE}) |
| 65 | +entry = check(r, 200) |
| 66 | +assert entry == {"platform": PLATFORM, "acquisition_type": ACQUISITION_TYPE}, f"unexpected entry: {entry}" |
| 67 | +print(f" entry: {entry}") |
| 68 | + |
| 69 | +# --------------------------------------------------------------------------- |
| 70 | +# Step 2: POST again — dedupes, still 200 |
| 71 | +# --------------------------------------------------------------------------- |
| 72 | + |
| 73 | +sep("Step 2: POST /acquisition-types again (expect 200, idempotent dedupe)") |
| 74 | +r = requests.post(ACQUISITION_TYPES_URL, json={"platform": PLATFORM, "acquisition_type": ACQUISITION_TYPE}) |
| 75 | +check(r, 200) |
| 76 | + |
| 77 | +# --------------------------------------------------------------------------- |
| 78 | +# Step 3: GET /acquisition-types — verify the pair is present exactly once |
| 79 | +# --------------------------------------------------------------------------- |
| 80 | + |
| 81 | +sep("Step 3: GET /acquisition-types (verify pair present)") |
| 82 | +r = requests.get(ACQUISITION_TYPES_URL) |
| 83 | +entries = check(r, 200) |
| 84 | +matches = [e for e in entries if e == {"platform": PLATFORM, "acquisition_type": ACQUISITION_TYPE}] |
| 85 | +assert len(matches) == 1, f"expected exactly 1 match, found {len(matches)} in {len(entries)} entries" |
| 86 | +print(f" found {len(matches)} matching entry among {len(entries)} total") |
| 87 | + |
| 88 | +# --------------------------------------------------------------------------- |
| 89 | +# Step 4: POST /scheduled-acquisitions with an unregistered acquisition_type → 400 |
| 90 | +# --------------------------------------------------------------------------- |
| 91 | + |
| 92 | +sep("Step 4: POST /scheduled-acquisitions with unknown acquisition_type (expect 400)") |
| 93 | +r = requests.post( |
| 94 | + SCHEDULED_ACQUISITIONS_URL, |
| 95 | + json={ |
| 96 | + "subject_id": SUBJECT_ID, |
| 97 | + "date": date.today().isoformat(), |
| 98 | + "acquisition_type": f"not-a-real-type-{int(time.time())}", |
| 99 | + }, |
| 100 | +) |
| 101 | +check(r, 400) |
| 102 | + |
| 103 | +# --------------------------------------------------------------------------- |
| 104 | +# Step 5: POST /scheduled-acquisitions with a missing field → 422 (typed body) |
| 105 | +# --------------------------------------------------------------------------- |
| 106 | + |
| 107 | +sep("Step 5: POST /scheduled-acquisitions missing acquisition_type (expect 422)") |
| 108 | +r = requests.post( |
| 109 | + SCHEDULED_ACQUISITIONS_URL, |
| 110 | + json={"subject_id": SUBJECT_ID, "date": date.today().isoformat()}, |
| 111 | +) |
| 112 | +check(r, 422) |
| 113 | + |
| 114 | +# --------------------------------------------------------------------------- |
| 115 | +# Step 6: POST /scheduled-acquisitions, date=today, our acquisition_type → 200 |
| 116 | +# --------------------------------------------------------------------------- |
| 117 | + |
| 118 | +sep("Step 6: POST /scheduled-acquisitions (date=today, expect 200 + uuid)") |
| 119 | +r = requests.post( |
| 120 | + SCHEDULED_ACQUISITIONS_URL, |
| 121 | + json={"subject_id": SUBJECT_ID, "date": date.today().isoformat(), "acquisition_type": ACQUISITION_TYPE}, |
| 122 | +) |
| 123 | +created = check(r, 200) |
| 124 | +assert "uuid" in created, f"missing uuid in response: {created}" |
| 125 | +today_uuid = created["uuid"] |
| 126 | +print(f" uuid: {today_uuid}") |
| 127 | + |
| 128 | +# --------------------------------------------------------------------------- |
| 129 | +# Step 7: GET /scheduled-acquisitions/{uuid} — verify full record |
| 130 | +# --------------------------------------------------------------------------- |
| 131 | + |
| 132 | +sep("Step 7: GET /scheduled-acquisitions/{uuid} (verify record)") |
| 133 | +r = requests.get(f"{SCHEDULED_ACQUISITIONS_URL}/{today_uuid}") |
| 134 | +record = check(r, 200) |
| 135 | +assert record["subject_id"] == SUBJECT_ID, f"unexpected subject_id: {record}" |
| 136 | +assert record["date"] == date.today().isoformat(), f"unexpected date: {record}" |
| 137 | +assert record["platform"] == PLATFORM, f"expected platform resolved to 'test', got {record}" |
| 138 | +assert record["acquisition_type"] == ACQUISITION_TYPE, f"unexpected acquisition_type: {record}" |
| 139 | +print(f" record: {record}") |
| 140 | + |
| 141 | +# --------------------------------------------------------------------------- |
| 142 | +# Step 8: GET /scheduled-acquisitions/{made-up-uuid} → 404 |
| 143 | +# --------------------------------------------------------------------------- |
| 144 | + |
| 145 | +sep("Step 8: GET /scheduled-acquisitions/{made-up-uuid} (expect 404)") |
| 146 | +r = requests.get(f"{SCHEDULED_ACQUISITIONS_URL}/not-a-real-uuid-{int(time.time())}") |
| 147 | +check(r, 404) |
| 148 | + |
| 149 | +# --------------------------------------------------------------------------- |
| 150 | +# Step 9: GET /scheduled-acquisitions (default, future-only) — today's uuid present |
| 151 | +# --------------------------------------------------------------------------- |
| 152 | + |
| 153 | +sep("Step 9: GET /scheduled-acquisitions (future-only, today's uuid should appear)") |
| 154 | +r = requests.get(SCHEDULED_ACQUISITIONS_URL) |
| 155 | +future_records = check(r, 200) |
| 156 | +future_uuids = {rec["uuid"] for rec in future_records} |
| 157 | +assert today_uuid in future_uuids, f"today's uuid {today_uuid} missing from future-only list" |
| 158 | +print(f" today's uuid present among {len(future_records)} future records") |
| 159 | + |
| 160 | +# --------------------------------------------------------------------------- |
| 161 | +# Step 10: POST /scheduled-acquisitions, date=yesterday (past) — second uuid |
| 162 | +# --------------------------------------------------------------------------- |
| 163 | + |
| 164 | +sep("Step 10: POST /scheduled-acquisitions (date=yesterday, expect 200 + uuid)") |
| 165 | +yesterday = (date.today() - timedelta(days=1)).isoformat() |
| 166 | +r = requests.post( |
| 167 | + SCHEDULED_ACQUISITIONS_URL, |
| 168 | + json={"subject_id": SUBJECT_ID, "date": yesterday, "acquisition_type": ACQUISITION_TYPE}, |
| 169 | +) |
| 170 | +created_past = check(r, 200) |
| 171 | +past_uuid = created_past["uuid"] |
| 172 | +print(f" uuid: {past_uuid}") |
| 173 | + |
| 174 | +# --------------------------------------------------------------------------- |
| 175 | +# Step 11: GET /scheduled-acquisitions (default, future-only) — past uuid excluded |
| 176 | +# --------------------------------------------------------------------------- |
| 177 | + |
| 178 | +sep("Step 11: GET /scheduled-acquisitions (future-only, past uuid should be excluded)") |
| 179 | +r = requests.get(SCHEDULED_ACQUISITIONS_URL) |
| 180 | +future_records = check(r, 200) |
| 181 | +future_uuids = {rec["uuid"] for rec in future_records} |
| 182 | +assert past_uuid not in future_uuids, f"past uuid {past_uuid} unexpectedly present in future-only list" |
| 183 | +assert today_uuid in future_uuids, "today's uuid should still be present" |
| 184 | +print(f" past uuid correctly excluded; today's uuid still present ({len(future_records)} future records)") |
| 185 | + |
| 186 | +# --------------------------------------------------------------------------- |
| 187 | +# Step 12: GET /scheduled-acquisitions?include_past=true — both uuids present |
| 188 | +# --------------------------------------------------------------------------- |
| 189 | + |
| 190 | +sep("Step 12: GET /scheduled-acquisitions?include_past=true (both uuids should appear)") |
| 191 | +r = requests.get(SCHEDULED_ACQUISITIONS_URL, params={"include_past": "true"}) |
| 192 | +all_records = check(r, 200) |
| 193 | +all_uuids = {rec["uuid"] for rec in all_records} |
| 194 | +assert today_uuid in all_uuids, "today's uuid missing from include_past=true list" |
| 195 | +assert past_uuid in all_uuids, "past uuid missing from include_past=true list" |
| 196 | +print(f" both uuids present among {len(all_records)} total records") |
| 197 | + |
| 198 | +print("\n" + "=" * 60) |
| 199 | +print(" ALL STEPS PASSED") |
| 200 | +print("=" * 60) |
0 commit comments