email-connect/tests/test_ledger_notifications.py
tegwick 93b6ba2aae
Some checks failed
Transactional mail acceptance / mail (push) Failing after 32s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 57s
Prepare glob-scoped callers and prove offsite ledger recovery
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a11fd9-caf6-7a63-b578-9daaaa134ff2
2026-10-09 11:43:11 +02:00

67 lines
2.8 KiB
Python

"""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"})