"""Synthetic integration only: no OHIP/source adapter, real DB or cloud store.""" import hashlib import json import tempfile import threading import time import unittest from datetime import date from pathlib import Path from arr_ingestion.repository import InMemoryIngestionRepository from arr_ingestion.service import IngestionService from arr_ingestion.validation import DeliveryValidator from arr_processing.policy import load_processor_policy from arr_storage.filesystem import FilesystemObjectBackend from arr_storage.store import ManagedObjectStore from arr_web.app import PortalApplication from arr_web.arr_download_handoff import outcome_from_handoff from arr_web.arr_downloads import PersistentARRDownloads from arr_web.programmatic import ProgrammaticUploadCoordinator from arr_web.repository import UnavailablePortalRepository from integrations.ohip import processing_handoff as handoff from tests.test_arr_opera_daily_ingest import reservation, xml_document from tests.test_arr_web import TEST_CREDENTIALS, login from tests.test_ohip_processing_handoff import CountingProcessor DAY = date(2026, 9, 15) REQUEST_ID = "a" * 32 class FixtureExecutor: """Test adapter uses declared synthetic XML; never imported by the runtime.""" def __init__(self, root, policy, store, repository, service): self.root, self.policy, self.store = root, policy, store self.repository, self.service = repository, service self.processor = CountingProcessor(policy) self.calls = [] self.payload = self.xml() self.prepared = self.receipt = None self.after_commit_error_once = False self.entered, self.release = threading.Event(), threading.Event() self.release.set() @staticmethod def xml(**kwargs): return xml_document(reservation(1, **kwargs)).replace( "2026-07-27", DAY.isoformat() ).replace("2026-07-28", "2026-09-16").replace( "20260727", "20260915" ).replace("27-07-26", "15-09-26").encode() def execute(self, *, request_id, from_date, to_date, report_stage): self.calls.append((request_id, from_date, to_date)) self.entered.set() if not self.release.wait(5): raise RuntimeError("fixture wait expired") if from_date != to_date: raise ValueError("fixture requires one day") binding = handoff.CaptureBinding(request_id, "SYNTHETIC", from_date.isoformat(), "b" * 64, "synthetic-xml-fixture/v1") report_stage("processing") self.prepared = handoff.prepare(self.root / "handoffs", binding, "ARR.XML", self.payload, self.policy, processor=self.processor) self.receipt = handoff.deliver(Path(self.prepared["directory"]), self.prepared["manifest_sha256"], object_store=self.store, repository=self.repository, service=self.service) if self.after_commit_error_once: self.after_commit_error_once = False raise ConnectionError("synthetic lost acknowledgement with private details") return outcome_from_handoff(self.receipt, job_id=binding.job_id, report_date=from_date, manifest_sha256=self.prepared["manifest_sha256"]) class MemoryTrace(UnavailablePortalRepository): def __init__(self, repository): self.repository = repository def get_job_trace(self, job_id): return {"job": {"status": self.repository._jobs[job_id].status}} class HandoffIntegrationTests(unittest.TestCase): @classmethod def setUpClass(cls): cls.policy = load_processor_policy(Path(__file__).resolve().parents[1]) def setUp(self): self.temp = tempfile.TemporaryDirectory() self.root = Path(self.temp.name) self.repository = InMemoryIngestionRepository() self.store = ManagedObjectStore(FilesystemObjectBackend(self.root / "objects", create=True)) self.ingestion = IngestionService(DeliveryValidator(self.store, self.policy), self.repository) self.executor = FixtureExecutor(self.root, self.policy, self.store, self.repository, self.ingestion) self.start_web() def start_web(self): self.queue = PersistentARRDownloads(self.root / "queue", self.executor) self.app = PortalApplication(repository=MemoryTrace(self.repository), arr_downloads=self.queue, credentials=TEST_CREDENTIALS) _, self.headers = login(self.app) def tearDown(self): self.executor.release.set() self.queue.close() self.temp.cleanup() def post(self, path="/api/arr-downloads", payload=None): response = self.app.handle("POST", path, self.headers, json.dumps( payload if payload is not None else {"report_date": DAY.isoformat(), "request_id": REQUEST_ID} ).encode()) self.assertEqual(response.status, 202, response.body) return json.loads(response.body)["data"] def finished(self): deadline = time.monotonic() + 15 while time.monotonic() < deadline: response = self.app.handle("GET", "/api/arr-downloads/" + REQUEST_ID, self.headers) self.assertEqual(response.status, 200) result = json.loads(response.body)["data"] if result["status"] not in {"queued", "downloading", "processing"}: return result time.sleep(.01) self.fail("integration worker did not settle") def frozen_hashes(self): root = Path(self.executor.prepared["directory"]) / "frozen" return {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest() for p in root.rglob("*") if p.is_file()} def test_selected_day_reaches_processing_and_double_click_commits_once(self): self.executor.release.clear() self.post() self.assertTrue(self.executor.entered.wait(1)) second = self.post(payload={"report_date": DAY.isoformat(), "request_id": "c" * 32}) self.assertEqual(second["request_id"], REQUEST_ID) self.executor.release.set() result = self.finished() self.assertEqual(result["status"], "succeeded") self.assertEqual(self.executor.calls, [(REQUEST_ID, DAY, DAY)]) self.assertEqual(self.executor.receipt["business_date"], DAY.isoformat()) self.assertEqual(result["job_id"], self.executor.receipt["job_id"]) self.assertEqual(len(self.repository._versions), 1) self.assertEqual(self.post()["job_id"], result["job_id"]) self.assertEqual(self.executor.processor.calls, 1) def test_restart_and_lost_ack_retry_keep_one_version_and_identical_artifacts(self): self.executor.after_commit_error_once = True self.post() interrupted = self.finished() self.assertEqual(interrupted["status"], "interrupted") self.assertNotIn("private", json.dumps(interrupted)) before = self.frozen_hashes() self.assertEqual(len(self.repository._versions), 1) self.queue.close() self.start_web() self.assertEqual(self.finished()["status"], "interrupted") self.post("/api/arr-downloads/" + REQUEST_ID + "/retry", {}) self.assertEqual(self.finished()["status"], "succeeded") self.assertEqual(self.executor.calls, [(REQUEST_ID, DAY, DAY)] * 2) self.assertEqual(self.frozen_hashes(), before) self.assertEqual(self.executor.processor.calls, 1) self.assertEqual((len(self.repository._jobs), len(self.repository._callbacks), len(self.repository._versions)), (1, 1, 1)) def test_price_review_is_persisted_without_finance_or_download_retry(self): self.executor.payload = self.executor.xml(rate_amount="1800") self.post() result = self.finished() self.assertEqual(result["status"], "needs_review") self.assertFalse(result["can_retry"]) self.assertIn(result["job_id"], self.repository._reviews) self.assertFalse(self.repository._versions) self.post("/api/arr-downloads/" + REQUEST_ID + "/retry", {}) self.assertEqual(len(self.executor.calls), 1) def test_authoritative_business_failure_does_not_become_success(self): self.executor.payload = self.executor.xml(departure="2026-09-14") self.post() result = self.finished() self.assertEqual(result["status"], "failed") self.assertFalse(result["can_retry"]) self.assertEqual(self.repository._jobs[result["job_id"]].status, "failed") self.assertFalse(self.repository._versions) def test_finished_manual_review_updates_web_status_without_recapturing(self): self.executor.payload = self.executor.xml(rate_amount="1800") self.post() task = self.finished() self.assertEqual(task["status"], "needs_review") review_service = ProgrammaticUploadCoordinator( object_store=self.store, ingestion_repository=self.repository, ingestion_service=self.ingestion, processor=self.executor.processor, processor_version=self.policy.processor_version, rule_set_sha256=self.policy.rule_set_sha256, ) review = review_service.get_price_review(task["job_id"], 50, 0) updated = review_service.update_price_review_item( task["job_id"], review["items"][0]["item_id"], review["case_id"], review["revision"], "0", "synthetic-reviewer", ) result = review_service.finalize_price_review( task["job_id"], updated["case_id"], updated["revision"], "synthetic-reviewer", ) self.assertEqual(result["status"], "succeeded") self.assertEqual(self.finished()["status"], "succeeded") self.assertEqual(self.finished()["job_id"], task["job_id"]) self.assertEqual(len(self.executor.calls), 1) self.assertEqual(len(self.repository._versions), 1) def test_changed_source_on_retry_cannot_create_another_finance_version(self): self.executor.after_commit_error_once = True self.post() self.assertEqual(self.finished()["status"], "interrupted") before = self.frozen_hashes() self.executor.payload += b"\n" self.post("/api/arr-downloads/" + REQUEST_ID + "/retry", {}) self.assertEqual(self.finished()["status"], "interrupted") self.assertEqual(self.frozen_hashes(), before) self.assertEqual(len(self.repository._versions), 1) self.assertEqual(self.executor.processor.calls, 1) def test_mismatched_or_unknown_receipt_is_rejected(self): self.post() self.assertEqual(self.finished()["status"], "succeeded") receipt = self.executor.receipt for changes in ( {"job_id": "different-job"}, {"manifest_sha256": "c" * 64}, {"business_date": "2026-09-16"}, {"version": "unknown"}, {"delivery_id": "other-delivery"}, {"ingestion_status": "candidate_capture_complete"}, {"ingestion_status": "future-status"}, {"daily_version_id": None}, {"daily_version_id": True}, {"version_no": 0}, {"ingestion_status": "recorded_review"}, {"daily_version_id": "1"}, {"version_no": -1}, ): with self.subTest(changes=changes), self.assertRaises(ValueError): outcome_from_handoff({**receipt, **changes}, job_id=receipt["job_id"], report_date=DAY, manifest_sha256=self.executor.prepared["manifest_sha256"]) failure = {**receipt, "ingestion_status": "recorded_failure", "business_date": None, "daily_version_id": None, "version_no": None} outcome = outcome_from_handoff(failure, job_id=receipt["job_id"], report_date=DAY, manifest_sha256=self.executor.prepared["manifest_sha256"]) self.assertEqual(outcome.status, "failed") self.assertFalse(outcome.retryable) def test_failure_accepts_rejected_audit_id_but_not_committed_version(self): self.executor.payload = self.executor.xml(rate_code="NOT-ALLOWED") self.post() self.assertEqual(self.finished()["status"], "failed") receipt = self.executor.receipt expected = dict(job_id=receipt["job_id"], report_date=DAY, manifest_sha256=receipt["manifest_sha256"]) for audit_id in (None, 17): with self.subTest(audit_id=audit_id): outcome = outcome_from_handoff({**receipt, "daily_version_id": audit_id}, **expected) self.assertEqual(outcome.status, "failed") self.assertEqual(outcome.job_id, receipt["job_id"]) self.assertFalse(outcome.retryable) for audit_id in (True, False, 0, -1, 17.0, "17", {}, []): with self.subTest(invalid_audit_id=audit_id), self.assertRaises(ValueError): outcome_from_handoff({**receipt, "daily_version_id": audit_id}, **expected) for changes in ({"version_no": 1}, {"version_no": 0}, {"version_no": False}, {"ingestion_status": "recorded_review"}, {"business_date": "2026-09-16"}): with self.subTest(changes=changes), self.assertRaises(ValueError): outcome_from_handoff({**receipt, "daily_version_id": 17, **changes}, **expected) if __name__ == "__main__": unittest.main()