"""Inbox notification failure/replay with synthetic receipts; no live messages.""" import importlib.util import json from pathlib import Path import pytest @pytest.fixture def notifier(monkeypatch): scripts = Path(__file__).resolve().parents[1] / "scripts" monkeypatch.syspath_prepend(str(scripts)) spec = importlib.util.spec_from_file_location("ledger_notifier", scripts / "notify-ledger-failure.py") module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def test_outage_preserves_private_pending_notice_and_replay_delivers(notifier, tmp_path): state = tmp_path / "outbox" def down(base, message): raise OSError("synthetic HTTP failure") with pytest.raises(OSError): notifier.notify(state, "http://synthetic.invalid", next(iter(notifier.UNITS)), sender=down) path, = state.glob("*.json") pending = json.loads(path.read_text()) assert pending["status"] == "pending" assert state.stat().st_mode & 0o777 == 0o700 assert path.stat().st_mode & 0o777 == 0o600 sent = [] def accepted(base, message): sent.append(message) return "00000000-0000-0000-0000-000000000001" receipt = notifier.notify(state, "http://synthetic.invalid", sender=accepted) assert receipt["recipient"] == "platform-root" assert receipt["human_acknowledged"] is False assert json.loads(path.read_text())["status"] == "delivered" assert json.loads(sent[0]["body"])["event_id"] == pending["event_id"] notifier.notify(state, "http://synthetic.invalid", sender=accepted) assert len(sent) == 1 def test_unexpected_unit_is_rejected_before_outbox_mutation(notifier, tmp_path): with pytest.raises(notifier.Refused, match="invalid_notification_unit"): notifier.notify(tmp_path / "unused", "http://synthetic.invalid", "other.service") assert not (tmp_path / "unused").exists() def test_failure_hook_test_is_labelled_without_real_failure_claim(notifier, tmp_path): sent = [] def accepted(base, message): sent.append(message) return "00000000-0000-0000-0000-000000000001" notifier.notify(tmp_path / "outbox", "http://synthetic.invalid", notifier.TEST_UNIT, sender=accepted) assert json.loads(sent[0]["body"])["test"] is True assert sent[0]["subject"].endswith("notification test") def test_queued_response_is_not_central_inbox_delivery(notifier, monkeypatch): class Response: def __enter__(self): return self def __exit__(self, *args): pass def read(self, *args): return b'{"status":"queued","receipt_id":"synthetic"}' monkeypatch.setattr(notifier, "urlopen", lambda *args, **kwargs: Response()) with pytest.raises(notifier.Refused, match="inbox_receipt_not_verified"): notifier.post("http://synthetic.invalid", {"subject": "synthetic", "body": "synthetic"})