from datetime import timedelta from unittest import mock import pytest from django.utils import timezone from infrasynth.notifications.models import NotificationDispatch from infrasynth.notifications.tasks import purge_old_dispatches, retry_pending_dispatches pytestmark = pytest.mark.django_db def _dispatch(tenant, **kwargs): defaults = { "tenant": tenant, "recipient": "user@example.com", "channel": "email", "subject": "S", "body": "B", "status": NotificationDispatch.Status.RETRYING, } defaults.update(kwargs) return NotificationDispatch.all_objects.create(**defaults) class TestRetryPendingDispatches: def test_requeues_due_dispatches(self, tenant): due = _dispatch(tenant, next_retry_at=timezone.now() - timedelta(minutes=1)) _dispatch(tenant, next_retry_at=timezone.now() + timedelta(hours=1)) with mock.patch("infrasynth.notifications.tasks.deliver_notification.delay") as delay: count = retry_pending_dispatches() assert count == 1 delay.assert_called_once_with(due.id, str(tenant.pk)) def test_ignores_sent_dispatches(self, tenant): _dispatch( tenant, status=NotificationDispatch.Status.SENT, next_retry_at=timezone.now() - timedelta(minutes=1), ) with mock.patch("infrasynth.notifications.tasks.deliver_notification.delay") as delay: assert retry_pending_dispatches() == 0 delay.assert_not_called() class TestPurgeOldDispatches: def test_deletes_only_finished_and_old(self, tenant): old_sent = _dispatch(tenant, status=NotificationDispatch.Status.SENT) NotificationDispatch.all_objects.filter(pk=old_sent.pk).update(created_at=timezone.now() - timedelta(days=400)) pending = _dispatch(tenant, status=NotificationDispatch.Status.PENDING) purge_old_dispatches() assert not NotificationDispatch.all_objects.filter(pk=old_sent.pk).exists() assert NotificationDispatch.all_objects.filter(pk=pending.pk).exists()