import pytest from types import SimpleNamespace from datetime import timedelta from django.contrib import admin from django.utils import timezone from apps.events.admin import EventAdmin, RegistrationAdmin from apps.events.models import Event, Registration, RegistrationNotification from apps.events.tasks import send_registration_cancellation_notification, send_registration_confirmation_notification from apps.events.tasks import deliver_pending_registration_notifications from apps.users.models import User @pytest.mark.django_db @pytest.mark.integration class TestEventModelTests: def setup_method(self): now = timezone.now() self.event = Event.objects.create(title='Workshop', description='**Important** details', start_time=now + timedelta(days=1), end_time=now + timedelta(days=1, hours=2), capacity=1, registration_start_date=now - timedelta(days=1), registration_end_date=now + timedelta(hours=1), is_published=True) self.user = User.objects.create_user(username='attendee', mobile='09191110003', password='password') def test_markdown_description_and_registration_window_remain_available(self): assert 'Important' in self.event.description_html assert self.event.is_registration_open self.event.registration_end_date = timezone.now() - timedelta(minutes=1) assert not self.event.is_registration_open def test_capacity_counts_confirmed_registration(self, mocker): delay = mocker.patch('apps.events.tasks.send_registration_confirmation_notification.delay') registration = Registration.objects.create(event=self.event, user=self.user, status=Registration.StatusChoices.CONFIRMED) assert self.event.current_attendees_count == 1 assert not self.event.has_available_slots assert RegistrationNotification.objects.filter( registration=registration, kind=RegistrationNotification.Kind.CONFIRMED, ).exists() delay.assert_not_called() def test_notification_worker_retries_after_redis_failure(self, mocker): registration = Registration.objects.create( event=self.event, user=self.user, status=Registration.StatusChoices.CONFIRMED, ) entry = RegistrationNotification.objects.get(registration=registration) notify = mocker.patch("apps.events.tasks.notify_user", side_effect=ConnectionError("redis unavailable")) assert deliver_pending_registration_notifications() == 0 entry.refresh_from_db() assert entry.delivered_at is None notify.side_effect = None assert deliver_pending_registration_notifications() == 1 entry.refresh_from_db() registration.refresh_from_db() assert entry.delivered_at is not None assert registration.confirmation_notification_sent_at is not None assert notify.call_args.args[1]["id"] == f"registration-{entry.pk}-confirmed" assert deliver_pending_registration_notifications() == 0 def test_unlimited_capacity_allows_registration(self): self.event.capacity = None assert self.event.has_available_slots