97 lines
3.8 KiB
Python
97 lines
3.8 KiB
Python
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()
|