1+ import smtplib
12from unittest .mock import patch
3+ from uuid import uuid4
24import time_machine
35from django .core import mail
4- from notifications .tasks import send_pending_emails
6+ from notifications .tasks import send_pending_email , send_pending_email_failed
57from notifications .models import SentEmail
68from notifications .tests .factories import SentEmailFactory
79
810
9- def test_send_pending_emails_does_nothing_with_no_pending_emails ():
10- SentEmailFactory (status = SentEmail .Status .sent , sent_at = "2020-01-01 12:00Z" )
11- SentEmailFactory (status = SentEmail .Status .sent , sent_at = "2020-01-01 12:00Z" )
12- SentEmailFactory (status = SentEmail .Status .sent , sent_at = "2020-01-01 12:00Z" )
13- SentEmailFactory (status = SentEmail .Status .sent , sent_at = "2020-01-01 12:00Z" )
11+ def test_send_pending_email_does_nothing_with_non_pending_email ():
12+ sent_email = SentEmailFactory (
13+ status = SentEmail .Status .sent , sent_at = "2020-01-01 12:00Z"
14+ )
1415
15- send_pending_emails ( )
16+ send_pending_email ( sent_email . id )
1617
1718 assert len (mail .outbox ) == 0
1819
1920
20- def test_send_pending_emails_task_sends_data_correctly ():
21+ def test_send_pending_email_task_sends_data_correctly ():
2122 pending_email_1 = SentEmailFactory (
2223 status = SentEmail .Status .pending ,
2324@@ -29,7 +30,8 @@ def test_send_pending_emails_task_sends_data_correctly():
2930 subject = "subject" ,
3031 )
3132
32- send_pending_emails ()
33+ with time_machine .travel ("2021-01-01 12:00Z" , tick = False ):
34+ send_pending_email (pending_email_1 .id )
3335
3436 assert len (mail .outbox ) == 1
3537
@@ -42,8 +44,16 @@ def test_send_pending_emails_task_sends_data_correctly():
4244 assert mail .outbox [0 ].alternatives == [("html body" , "text/html" )]
4345 assert mail .outbox [0 ].subject == "subject"
4446
47+ pending_email_1 .refresh_from_db ()
48+
49+ assert len (mail .outbox ) == 1
50+
51+ assert pending_email_1 .status == SentEmail .Status .sent
52+ assert pending_email_1 .message_id .startswith ("local-" )
53+ assert pending_email_1 .sent_at .isoformat () == "2021-01-01T12:00:00+00:00"
54+
4555
46- def test_send_pending_emails_task_doesnt_double_send ():
56+ def test_send_pending_email_task_doesnt_double_send ():
4757 pending_email_1 = SentEmailFactory (status = SentEmail .Status .pending )
4858 original_qs = SentEmail .objects .select_for_update (skip_locked = True ).filter (
4959 id = pending_email_1 .id
@@ -57,81 +67,28 @@ def side_effect(*args, **kwargs):
5767 "notifications.tasks.SentEmail.objects.select_for_update" ,
5868 side_effect = side_effect ,
5969 ):
60- send_pending_emails ( )
70+ send_pending_email ( pending_email_1 . id )
6171
6272 pending_email_1 .refresh_from_db ()
6373
6474 assert len (mail .outbox ) == 0
6575
6676
67- def test_send_pending_emails_task ():
68- pending_email_1 = SentEmailFactory (status = SentEmail .Status .pending )
69- pending_email_2 = SentEmailFactory (status = SentEmail .Status .pending )
70- sent_email_1 = SentEmailFactory (
71- status = SentEmail .Status .sent , message_id = "abc-abc" , sent_at = "2020-01-01 12:00Z"
72- )
73-
74- with time_machine .travel ("2021-01-01 12:00Z" , tick = False ):
75- send_pending_emails ()
76-
77- pending_email_1 .refresh_from_db ()
78- pending_email_2 .refresh_from_db ()
79- sent_email_1 .refresh_from_db ()
80-
81- assert len (mail .outbox ) == 2
82-
83- assert mail .outbox [0 ].to == [pending_email_1 .recipient_email ]
84- assert mail .outbox [1 ].to == [pending_email_2 .recipient_email ]
85-
86- assert pending_email_1 .status == SentEmail .Status .sent
87- assert pending_email_1 .message_id .startswith ("local-" )
88- assert pending_email_1 .sent_at .isoformat () == "2021-01-01T12:00:00+00:00"
89-
90- assert pending_email_2 .status == SentEmail .Status .sent
91- assert pending_email_2 .message_id .startswith ("local-" )
92- assert pending_email_2 .sent_at .isoformat () == "2021-01-01T12:00:00+00:00"
93-
94- assert sent_email_1 .status == SentEmail .Status .sent
95- assert sent_email_1 .message_id == "abc-abc"
96- assert sent_email_1 .sent_at .isoformat () == "2020-01-01T12:00:00+00:00"
97-
98-
99- def test_send_pending_emails_handles_failures (mocker ):
77+ def test_send_pending_email_failure ():
10078 pending_email_1 = SentEmailFactory (
10179 status = SentEmail .Status .pending , created = "2020-01-01 12:00Z"
10280 )
103- pending_email_2 = SentEmailFactory (
104- status = SentEmail .Status .pending , created = "2020-01-02 12:00Z"
105- )
106-
107- original_method = SentEmail .mark_as_sent
108-
109- def _side_effect (* args , ** kwargs ):
110- if _side_effect .counter == 0 :
111- _side_effect .counter = 1
112- raise ValueError ("test" )
11381
114- return original_method ( pending_email_2 , * args , ** kwargs )
115-
116- _side_effect . counter = 0
117-
118- mocker . patch ( "notifications.tasks.SentEmail.mark_as_sent" , side_effect = _side_effect )
119-
120- with time_machine . travel ( "2021-01-01 12:00Z" , tick = False ):
121- send_pending_emails ( )
82+ send_pending_email_failed (
83+ None ,
84+ smtplib . SMTPException ( "test" ),
85+ uuid4 (). hex ,
86+ ( pending_email_1 . id ,),
87+ {},
88+ None ,
89+ )
12290
12391 pending_email_1 .refresh_from_db ()
124- pending_email_2 .refresh_from_db ()
125-
126- assert len (mail .outbox ) == 2
127-
128- assert mail .outbox [0 ].to == [pending_email_1 .recipient_email ]
129- assert mail .outbox [1 ].to == [pending_email_2 .recipient_email ]
13092
93+ assert len (mail .outbox ) == 0
13194 assert pending_email_1 .status == SentEmail .Status .failed
132- assert pending_email_1 .message_id == ""
133- assert pending_email_1 .sent_at is None
134-
135- assert pending_email_2 .status == SentEmail .Status .sent
136- assert pending_email_2 .message_id .startswith ("local-" )
137- assert pending_email_2 .sent_at .isoformat () == "2021-01-01T12:00:00+00:00"
0 commit comments