from __future__ import annotations import unittest from datetime import datetime, timedelta, timezone from fluxer_admin_alerts.engine import decide from fluxer_admin_alerts.sources import Item from fluxer_admin_alerts.state import AlertRecord NOW = datetime(2026, 1, 10, 12, 0, tzinfo=timezone.utc) REALERT = timedelta(hours=12) SOURCE = "pending_registrations" def make_item(opened_at=None, reminder_after=None) -> Item: return Item( key="registration:1", title="Account waiting for approval", detail="User: test", path="/registrations", opened_at=opened_at, reminder_after=reminder_after, ) def run_decide(now, items, known, checked=frozenset({SOURCE}), realert=REALERT, notify_cleared=True): seen = {item.key: (SOURCE, item) for item in items} return decide(now, seen, known, set(checked), realert, notify_cleared) def as_known(plan): return {r.key: r for r in plan.records} class DecideTests(unittest.TestCase): def test_new_item_alerts_once(self): first = run_decide(NOW, [make_item()], {}) self.assertEqual([n.kind for n in first.notices], ["new"]) second = run_decide(NOW + timedelta(hours=1), [make_item()], as_known(first)) self.assertEqual(second.notices, []) def test_repeats_after_realert_interval(self): first = run_decide(NOW, [make_item()], {}) later = run_decide(NOW + timedelta(hours=12), [make_item()], as_known(first)) self.assertEqual([n.kind for n in later.notices], ["repeat"]) def test_realert_disabled(self): first = run_decide(NOW, [make_item()], {}, realert=None) later = run_decide(NOW + timedelta(days=30), [make_item()], as_known(first), realert=None) self.assertEqual(later.notices, []) def test_report_reminder_after_stale_threshold(self): report = make_item(opened_at=NOW, reminder_after=timedelta(hours=48)) first = run_decide(NOW, [report], {}) self.assertEqual([n.kind for n in first.notices], ["new"]) at_48h = run_decide(NOW + timedelta(hours=48), [report], as_known(first)) self.assertEqual([n.kind for n in at_48h.notices], ["reminder"]) at_60h = run_decide(NOW + timedelta(hours=60), [report], as_known(at_48h)) self.assertEqual([n.kind for n in at_60h.notices], ["repeat"]) def test_old_report_seen_first_time_does_not_double_alert(self): old = make_item(opened_at=NOW - timedelta(hours=72), reminder_after=timedelta(hours=48)) first = run_decide(NOW, [old], {}) self.assertEqual([n.kind for n in first.notices], ["new"]) second = run_decide(NOW + timedelta(hours=1), [old], as_known(first)) self.assertEqual(second.notices, []) def test_cleared_item_sends_notice_and_closes(self): first = run_decide(NOW, [make_item()], {}) gone = run_decide(NOW + timedelta(hours=1), [], as_known(first)) self.assertEqual([n.kind for n in gone.notices], ["cleared"]) self.assertFalse(gone.records[0].open) def test_cleared_notice_can_be_disabled(self): first = run_decide(NOW, [make_item()], {}) gone = run_decide(NOW + timedelta(hours=1), [], as_known(first), notify_cleared=False) self.assertEqual(gone.notices, []) self.assertFalse(gone.records[0].open) def test_unchecked_source_is_not_closed(self): first = run_decide(NOW, [make_item()], {}) skipped = run_decide(NOW + timedelta(hours=1), [], as_known(first), checked=set()) self.assertEqual(skipped.notices, []) self.assertEqual(skipped.records, []) def test_reopened_item_alerts_again(self): closed = AlertRecord("registration:1", SOURCE, "x", NOW, NOW, False, False) back = run_decide(NOW, [make_item()], {closed.key: closed}) self.assertEqual([n.kind for n in back.notices], ["new"]) if __name__ == "__main__": unittest.main()