Split backend tests into unit and integration suites, add isolated fixtures and coverage enforcement, and update CI and test documentation. Cover current authentication, content, notification, payment, media, and admin flows; fix behaviors revealed by the new tests. Validate both suites and the per-module gate against local PostgreSQL.
73 lines
4.1 KiB
Python
73 lines
4.1 KiB
Python
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
|
|
from apps.events.tasks import send_registration_cancellation_notification, send_registration_confirmation_notification
|
|
from apps.users.models import User
|
|
|
|
@pytest.mark.unit
|
|
class TestAutomaticRegistrationNotificationTests:
|
|
|
|
def test_confirmation_delivers_in_app_with_event_link(self, mocker):
|
|
registrations = mocker.patch('apps.events.tasks.Registration.objects')
|
|
notify_user = mocker.patch('apps.events.tasks.notify_user')
|
|
registration = SimpleNamespace(user_id=7, event_id=12, ticket_id='ticket', event=SimpleNamespace(title='Workshop', slug='workshop'))
|
|
registrations.select_related.return_value.get.return_value = registration
|
|
result = send_registration_confirmation_notification.run('1')
|
|
assert result == {'sent': True}
|
|
assert notify_user.call_args.args[0] == 7
|
|
assert notify_user.call_args.args[1]['action_url'] == '/events/workshop'
|
|
|
|
def test_cancellation_delivers_in_app_and_optional_sms(self, mocker):
|
|
registrations = mocker.patch('apps.events.tasks.Registration.objects')
|
|
notify_user = mocker.patch('apps.events.tasks.notify_user')
|
|
send_sms = mocker.patch('apps.events.tasks.send_critical_sms.delay')
|
|
registrations.select_related.return_value.get.return_value = SimpleNamespace(user_id=7, event_id=12, user=SimpleNamespace(mobile='09191110002', is_mobile_verified=True), event=SimpleNamespace(title='Workshop', slug='workshop'))
|
|
assert send_registration_cancellation_notification.run('1') == {'sent': True}
|
|
assert notify_user.call_args.args[1]['type'] == 'event_cancellation'
|
|
send_sms.assert_called_once_with('09191110002', 'event_cancellation', 'Workshop')
|
|
|
|
def test_cancellation_skips_sms_for_unverified_mobile(self, mocker):
|
|
registrations = mocker.patch('apps.events.tasks.Registration.objects')
|
|
mocker.patch('apps.events.tasks.notify_user')
|
|
send_sms = mocker.patch('apps.events.tasks.send_critical_sms.delay')
|
|
registrations.select_related.return_value.get.return_value = SimpleNamespace(
|
|
user_id=7, event_id=12,
|
|
user=SimpleNamespace(mobile='09191110002', is_mobile_verified=False),
|
|
event=SimpleNamespace(title='Workshop', slug='workshop'),
|
|
)
|
|
assert send_registration_cancellation_notification.run('1') == {'sent': True}
|
|
send_sms.assert_not_called()
|
|
|
|
def test_confirmation_failure_requests_retry(self, mocker):
|
|
registrations = mocker.patch('apps.events.tasks.Registration.objects')
|
|
registrations.select_related.return_value.get.side_effect = Registration.DoesNotExist()
|
|
retry = mocker.patch.object(
|
|
send_registration_confirmation_notification, 'retry', side_effect=RuntimeError('retry requested')
|
|
)
|
|
with pytest.raises(RuntimeError, match='retry requested'):
|
|
send_registration_confirmation_notification.run('missing')
|
|
assert retry.call_args.kwargs['countdown'] == 60
|
|
|
|
@pytest.mark.unit
|
|
class TestManualActionRemovalTests:
|
|
|
|
def test_event_and_registration_admin_have_no_manual_send_actions(self):
|
|
assert not EventAdmin.__dict__.get('actions_row')
|
|
assert not RegistrationAdmin.__dict__.get('actions_row')
|
|
|
|
def test_bulk_status_actions_save_each_registration_for_automatic_notification(self, mocker):
|
|
model_admin = RegistrationAdmin(Registration, admin.site)
|
|
registration = mocker.Mock()
|
|
mocker.patch.object(model_admin, 'message_user')
|
|
model_admin.confirm_registrations(SimpleNamespace(), [registration])
|
|
assert registration.status == Registration.StatusChoices.CONFIRMED
|
|
registration.save.assert_called_with(update_fields=['status'])
|
|
registration.reset_mock()
|
|
model_admin.cancel_registrations(SimpleNamespace(), [registration])
|
|
assert registration.status == Registration.StatusChoices.CANCELLED
|
|
registration.save.assert_called_with(update_fields=['status'])
|