"""Notification cooldown / dedup (notif-31).""" from datetime import datetime, timedelta, timezone from app.config import get_settings from app.models import Event from app.models.notification_cooldown import NotificationCooldown from app.services.notification_cooldown import ( allow_notify, build_event_cooldown_key, build_problem_cooldown_key, should_notify_event, ) from app.models import Problem def test_build_event_cooldown_key_prefers_dedup_key(): event = Event( event_id="00000000-0000-4000-8000-000000000601", host_id=1, occurred_at=datetime(2026, 5, 29, 16, 0, tzinfo=timezone.utc), category="auth", type="rdp.login.failed", severity="warning", title="t", summary="s", dedup_key="rdp|host|failed|10.0.0.1|admin", payload={}, ) assert build_event_cooldown_key(event) == "event:rdp|host|failed|10.0.0.1|admin" def test_allow_notify_blocks_within_cooldown(db_session, monkeypatch): monkeypatch.setenv("SAC_NOTIFY_COOLDOWN_ENABLED", "true") monkeypatch.setenv("SAC_NOTIFY_EVENT_COOLDOWN_SEC", "90") get_settings.cache_clear() key = "event:test-key" past = datetime.now(timezone.utc) - timedelta(seconds=30) db_session.add(NotificationCooldown(cooldown_key=key, kind="event", last_notified_at=past)) db_session.commit() assert allow_notify(db_session, key=key, kind="event") is False def test_allow_notify_allows_after_cooldown(db_session, monkeypatch): monkeypatch.setenv("SAC_NOTIFY_COOLDOWN_ENABLED", "true") monkeypatch.setenv("SAC_NOTIFY_EVENT_COOLDOWN_SEC", "60") get_settings.cache_clear() key = "event:old" past = datetime.now(timezone.utc) - timedelta(seconds=120) db_session.add(NotificationCooldown(cooldown_key=key, kind="event", last_notified_at=past)) db_session.commit() assert allow_notify(db_session, key=key, kind="event") is True def test_should_notify_event_exempt_agent_test(db_session, monkeypatch): monkeypatch.setenv("SAC_NOTIFY_EVENT_COOLDOWN_SEC", "90") get_settings.cache_clear() event = Event( event_id="00000000-0000-4000-8000-000000000602", host_id=1, occurred_at=datetime(2026, 5, 29, 16, 0, tzinfo=timezone.utc), category="agent", type="agent.test", severity="info", title="t", summary="s", payload={}, ) assert should_notify_event(event, db_session) is True def test_build_problem_cooldown_key(): problem = Problem( title="brute", summary="x", severity="high", status="open", fingerprint="host:1|rdp.login.failed|rule:brute", ) assert build_problem_cooldown_key(problem).startswith("problem:")