60 lines
3.0 KiB
Python
60 lines
3.0 KiB
Python
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()
|