|
1 | 1 | import datetime |
| 2 | +from io import StringIO |
| 3 | +from unittest import mock |
2 | 4 | import numpy as np |
3 | 5 | from django.test import TestCase |
4 | 6 | from django.utils import timezone |
| 7 | +from django.core.management import call_command |
5 | 8 |
|
6 | 9 | from alyx import base |
7 | 10 | from actions.water_control import to_date |
8 | 11 | from actions.models import ( |
9 | 12 | WaterAdministration, WaterRestriction, WaterType, Weighing, |
10 | | - Notification, NotificationRule, create_notification, Surgery, ProcedureType) |
| 13 | + Notification, NotificationRule, create_notification, Surgery, ProcedureType, |
| 14 | + send_pending_emails) |
11 | 15 | from actions.notifications import check_water_administration, check_weighed |
12 | 16 | from misc.models import LabMember, LabMembership, Lab |
13 | 17 | from subjects.models import Subject |
@@ -289,3 +293,81 @@ def _assert_users(users, expected): |
289 | 293 | nr.subjects_scope = 'none' |
290 | 294 | nr.save() |
291 | 295 | _assert_users([self.user2], [self.user2]) |
| 296 | + |
| 297 | + def test_send_pending_emails(self): |
| 298 | + """Test for sending pending notification emails.""" |
| 299 | + n1 = Notification.objects.create( |
| 300 | + title='Test notification 1', |
| 301 | + message='This is a test notification.', |
| 302 | + send_at=timezone.now() - datetime.timedelta(minutes=1) |
| 303 | + ) |
| 304 | + n2 = Notification.objects.create( |
| 305 | + title='Test notification 2', |
| 306 | + message='This is another test notification.', |
| 307 | + status='no-send', |
| 308 | + send_at=timezone.now() - datetime.timedelta(minutes=1) |
| 309 | + ) |
| 310 | + # Check ready_to_send method |
| 311 | + self.assertTrue(n1.ready_to_send()) |
| 312 | + self.assertFalse(n2.ready_to_send()) |
| 313 | + # Call the function to send pending emails |
| 314 | + with mock.patch('actions.models.alyx_mail', return_value=False) as mock_mail: |
| 315 | + send_pending_emails() |
| 316 | + # Should have been called once with the first notification |
| 317 | + mock_mail.assert_called_once_with([], n1.title, n1.message) |
| 318 | + json_field = Notification.objects.get(id=n1.id).json or {} |
| 319 | + self.assertIn('failed_attempts', json_field) |
| 320 | + self.assertEqual(len(json_field['failed_attempts']), 1) |
| 321 | + # Call the function to send pending emails |
| 322 | + with mock.patch('actions.models.alyx_mail', return_value=False) as mock_mail: |
| 323 | + send_pending_emails(max_resend=1) |
| 324 | + self.assertEqual('no-send', Notification.objects.get(id=n1.id).status) |
| 325 | + # Create two notifications to be sent |
| 326 | + Notification.objects.create( |
| 327 | + title='Test notification 3', |
| 328 | + message='This is a test notification.', |
| 329 | + send_at=timezone.now() - datetime.timedelta(minutes=1) |
| 330 | + ) |
| 331 | + Notification.objects.create( |
| 332 | + title='Test notification 4', |
| 333 | + message='This is another test notification.', |
| 334 | + send_at=timezone.now() - datetime.timedelta(minutes=1) |
| 335 | + ) |
| 336 | + with mock.patch('actions.models.alyx_mail', return_value=True) as mock_mail: |
| 337 | + send_pending_emails(max_resend=1) |
| 338 | + # Check that notifications are marked as emailed |
| 339 | + notifs = Notification.objects.filter(status='sent', sent_at__isnull=False) |
| 340 | + self.assertEqual(notifs.count(), 2) |
| 341 | + |
| 342 | + |
| 343 | +class TestManagementTasks(base.BaseTests): |
| 344 | + """Tests for the tasks management command.""" |
| 345 | + |
| 346 | + def test_send_pending_notifications_command(self): |
| 347 | + """Test for send_pending_notifications management command.""" |
| 348 | + out = StringIO() |
| 349 | + with mock.patch('actions.models.send_pending_emails') as mock_send: |
| 350 | + call_command('send_pending_notifications', stdout=out) |
| 351 | + mock_send.assert_called_once() |
| 352 | + |
| 353 | + def test_delete_expired_notifications_command(self): |
| 354 | + """Test for delete_expired_notifications management command.""" |
| 355 | + # Create some old notifications |
| 356 | + old_date = timezone.now() - datetime.timedelta(days=365) |
| 357 | + for i in range(5): |
| 358 | + Notification.objects.create( |
| 359 | + title=f'Old notification {i}', |
| 360 | + message='This is an old notification.', |
| 361 | + send_at=old_date, |
| 362 | + sent_at=old_date, |
| 363 | + status='sent' |
| 364 | + ) |
| 365 | + out = StringIO() |
| 366 | + call_command('delete_expired_notifications', |
| 367 | + n_days_old=180, status='sent', stdout=out, dry_run=True) |
| 368 | + self.assertIn('Dry run: 5 notifications found with status "sent"', out.getvalue()) |
| 369 | + self.assertEqual(Notification.objects.count(), 5) |
| 370 | + out = StringIO() |
| 371 | + call_command('delete_expired_notifications', n_days_old=180, status='sent', stdout=out) |
| 372 | + self.assertIn('Deleted 5 notifications with status "sent"', out.getvalue()) |
| 373 | + self.assertEqual(Notification.objects.count(), 0) |
0 commit comments