feat: prepare ARR for controlled public deployment
This commit is contained in:
192
tests/test_arr_ingestion_contracts.py
Normal file
192
tests/test_arr_ingestion_contracts.py
Normal file
@@ -0,0 +1,192 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import unittest
|
||||
|
||||
from arr_ingestion.contracts import DeliveryEnvelope, IngestionError
|
||||
|
||||
|
||||
SHA_A = "a" * 64
|
||||
SHA_B = "b" * 64
|
||||
SHA_C = "c" * 64
|
||||
SHA_D = "d" * 64
|
||||
SHA_E = "e" * 64
|
||||
|
||||
|
||||
def artifact(
|
||||
object_key: str,
|
||||
original_filename: str,
|
||||
sha256: str,
|
||||
byte_size: int,
|
||||
mime_type: str,
|
||||
) -> dict[str, object]:
|
||||
return {
|
||||
"object_key": object_key,
|
||||
"original_filename": original_filename,
|
||||
"sha256": sha256,
|
||||
"byte_size": byte_size,
|
||||
"mime_type": mime_type,
|
||||
}
|
||||
|
||||
|
||||
def success_envelope() -> dict[str, object]:
|
||||
return {
|
||||
"delivery_schema_version": "1.0",
|
||||
"delivery_id": "delivery-001",
|
||||
"job_id": "job-001",
|
||||
"attempt_no": 1,
|
||||
"status": "success",
|
||||
"processor_version": "3.0.0",
|
||||
"rule_set_sha256": SHA_A,
|
||||
"result_schema_version": "3.0",
|
||||
"business_date": "2026-07-27",
|
||||
"artifacts": {
|
||||
"source_xml": artifact(
|
||||
"arr/jobs/job-001/input/source.xml",
|
||||
"source.xml",
|
||||
SHA_A,
|
||||
100,
|
||||
"application/xml",
|
||||
),
|
||||
"daily_report": artifact(
|
||||
"arr/jobs/job-001/output/7.27.xlsx",
|
||||
"7.27.xlsx",
|
||||
SHA_B,
|
||||
200,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
),
|
||||
"result_json": artifact(
|
||||
"arr/jobs/job-001/output/result.json",
|
||||
"result.json",
|
||||
SHA_C,
|
||||
300,
|
||||
"application/json",
|
||||
),
|
||||
"structured_result_json": artifact(
|
||||
"arr/jobs/job-001/output/structured-result.json",
|
||||
"structured-result.json",
|
||||
SHA_D,
|
||||
400,
|
||||
"application/json",
|
||||
),
|
||||
"exception_report": None,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def failure_envelope() -> dict[str, object]:
|
||||
payload = success_envelope()
|
||||
payload["status"] = "failed"
|
||||
payload["business_date"] = None
|
||||
artifacts = payload["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
artifacts["daily_report"] = None
|
||||
artifacts["exception_report"] = artifact(
|
||||
"arr/jobs/job-001/output/exception.xlsx",
|
||||
"exception.xlsx",
|
||||
SHA_E,
|
||||
500,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
class DeliveryEnvelopeTests(unittest.TestCase):
|
||||
def test_success_contract_is_strict_and_typed(self):
|
||||
envelope = DeliveryEnvelope.from_dict(success_envelope())
|
||||
self.assertEqual(envelope.job_id, "job-001")
|
||||
self.assertEqual(envelope.attempt_no, 1)
|
||||
self.assertEqual(envelope.business_date.isoformat(), "2026-07-27")
|
||||
self.assertEqual(envelope.artifacts["source_xml"].file_kind, "opera_xml")
|
||||
self.assertIsNone(envelope.artifacts["exception_report"])
|
||||
|
||||
def test_failed_contract_requires_exception_and_forbids_daily(self):
|
||||
envelope = DeliveryEnvelope.from_dict(failure_envelope())
|
||||
self.assertEqual(envelope.status, "failed")
|
||||
self.assertIsNone(envelope.business_date)
|
||||
self.assertIsNone(envelope.artifacts["daily_report"])
|
||||
self.assertIsNotNone(envelope.artifacts["exception_report"])
|
||||
|
||||
missing_exception = failure_envelope()
|
||||
artifacts = missing_exception["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
artifacts["exception_report"] = None
|
||||
with self.assertRaisesRegex(IngestionError, "failed delivery"):
|
||||
DeliveryEnvelope.from_dict(missing_exception)
|
||||
|
||||
def test_extra_fields_and_monthly_artifacts_are_rejected(self):
|
||||
extra = success_envelope()
|
||||
extra["message"] = "not allowed"
|
||||
with self.assertRaisesRegex(IngestionError, "field set"):
|
||||
DeliveryEnvelope.from_dict(extra)
|
||||
|
||||
monthly = success_envelope()
|
||||
artifacts = monthly["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
artifacts["monthly_report"] = artifact(
|
||||
"arr/jobs/job-001/output/monthly.xlsx",
|
||||
"monthly.xlsx",
|
||||
SHA_E,
|
||||
500,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
)
|
||||
with self.assertRaisesRegex(IngestionError, "artifact field set"):
|
||||
DeliveryEnvelope.from_dict(monthly)
|
||||
|
||||
def test_object_keys_and_filenames_cannot_escape_or_impersonate_roles(self):
|
||||
invalid_keys = (
|
||||
"/absolute/source.xml",
|
||||
"../source.xml",
|
||||
"arr/jobs/../source.xml",
|
||||
"arr\\jobs\\source.xml",
|
||||
"arr//jobs/source.xml",
|
||||
)
|
||||
for invalid in invalid_keys:
|
||||
payload = success_envelope()
|
||||
artifacts = payload["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
source = artifacts["source_xml"]
|
||||
assert isinstance(source, dict)
|
||||
source["object_key"] = invalid
|
||||
with self.subTest(object_key=invalid):
|
||||
with self.assertRaises(IngestionError):
|
||||
DeliveryEnvelope.from_dict(payload)
|
||||
|
||||
bad_filename = success_envelope()
|
||||
artifacts = bad_filename["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
daily = artifacts["daily_report"]
|
||||
assert isinstance(daily, dict)
|
||||
daily["original_filename"] = "../7.27.xlsx"
|
||||
with self.assertRaises(IngestionError):
|
||||
DeliveryEnvelope.from_dict(bad_filename)
|
||||
|
||||
bad_mime = success_envelope()
|
||||
artifacts = bad_mime["artifacts"]
|
||||
assert isinstance(artifacts, dict)
|
||||
source = artifacts["source_xml"]
|
||||
assert isinstance(source, dict)
|
||||
source["mime_type"] = "text/plain"
|
||||
with self.assertRaisesRegex(IngestionError, "source_xml metadata"):
|
||||
DeliveryEnvelope.from_dict(bad_mime)
|
||||
|
||||
def test_contract_rejects_bad_versions_hashes_dates_and_identifiers(self):
|
||||
mutations = (
|
||||
("delivery_schema_version", "2.0"),
|
||||
("delivery_id", "contains spaces"),
|
||||
("attempt_no", 0),
|
||||
("processor_version", ""),
|
||||
("rule_set_sha256", "not-a-hash"),
|
||||
("result_schema_version", "2.0"),
|
||||
("business_date", "2026-02-30"),
|
||||
)
|
||||
for field, value in mutations:
|
||||
payload = copy.deepcopy(success_envelope())
|
||||
payload[field] = value
|
||||
with self.subTest(field=field):
|
||||
with self.assertRaises(IngestionError):
|
||||
DeliveryEnvelope.from_dict(payload)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user