import importlib.util from pathlib import Path import unittest spec = importlib.util.spec_from_file_location("pilot_run", Path(__file__).resolve().parents[1] / "deploy" / "pilot_run.py") pilot = importlib.util.module_from_spec(spec) spec.loader.exec_module(pilot) def valid_record(): days = [f"2026-10-{day:02d}" for day in range(5, 10)] return { "schemaVersion": 1, "system": "guestops-supervised-pilot", "targetGate": "B", "releaseCommit": "a" * 40, "releaseRecordSha256": "b" * 64, "environment": "https://sandbox-guestops.futuresens.co.uk", "hotelLabel": "pilot-hotel-a", "hotelCount": 1, "plannedBusinessDays": 5, "owners": {"hotelOwner": "Hotel owner", "technicalOwner": "Technical owner", "rollbackDecisionMaker": "Technical owner"}, "startedOn": days[0], "endedOn": days[-1], "pilotControls": {"pmsWrites": "disabled", "paymentCreation": "disabled", "faqMode": "off", "googleReviewedSending": "accepted"}, "dailyReviews": [{"date": day, "status": "pass", "reviewedBy": "Daily reviewer", "evidence": [f"restricted-{day}"]} for day in days], "stopConditions": {condition: False for condition in pilot.STOP_CONDITIONS}, "findings": [], "postPilotState": {"pmsWrites": "disabled", "paymentCreation": "disabled", "faqMode": "off"}, } class PilotRunTests(unittest.TestCase): def test_complete_five_day_record_passes(self): pilot.validate(valid_record()) def test_exact_business_days_are_required(self): record = valid_record();record["dailyReviews"].pop() with self.assertRaisesRegex(ValueError, "Exactly five"): pilot.validate(record) record = valid_record();record["dailyReviews"][1]["date"] = "2026-10-07" with self.assertRaisesRegex(ValueError, "each business day"): pilot.validate(record) def test_stop_condition_prevents_pass(self): record = valid_record();record["stopConditions"]["duplicate-send"] = True with self.assertRaisesRegex(ValueError, "stop condition"): pilot.validate(record) def test_critical_findings_cannot_be_contained(self): record = valid_record();record["findings"] = [{"id": "security-001", "severity": "critical", "disposition": "contained", "evidence": ["restricted-finding"]}] with self.assertRaisesRegex(ValueError, "too severe"): pilot.validate(record) def test_lower_severity_containment_requires_owner_expiry_and_trigger(self): record = valid_record();record["findings"] = [{"id": "usability-001", "severity": "low", "disposition": "contained", "evidence": ["restricted-finding"]}] with self.assertRaisesRegex(ValueError, "containment details"): pilot.validate(record) record["findings"][0]["containment"] = {"owner": "Finding owner", "expiresAt": "2026-10-31T12:00:00Z", "rollbackTrigger": "Stop if the issue affects guest handling."} pilot.validate(record) if __name__ == "__main__": unittest.main()