Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_mail.py 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from datetime import date, datetime
  4. from django.core import mail
  5. from django.core.files.base import ContentFile
  6. from django.conf import settings
  7. from django.test import TestCase
  8. from django.test.utils import override_settings
  9. from ..settings import get_batch_size, get_log_level, get_threads_per_process
  10. from ..models import Email, EmailTemplate, Attachment, PRIORITY, STATUS
  11. from ..mail import (create, get_queued,
  12. send, send_many, send_queued, _send_bulk)
  13. connection_counter = 0
  14. class ConnectionTestingBackend(mail.backends.base.BaseEmailBackend):
  15. '''
  16. An EmailBackend that increments a global counter when connection is opened
  17. '''
  18. def open(self):
  19. global connection_counter
  20. connection_counter += 1
  21. def send_messages(self, email_messages):
  22. pass
  23. class MailTest(TestCase):
  24. @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
  25. def test_send_queued_mail(self):
  26. """
  27. Check that only queued messages are sent.
  28. """
  29. kwargs = {
  30. 'to': ['to@example.com'],
  31. 'from_email': 'bob@example.com',
  32. 'subject': 'Test',
  33. 'message': 'Message',
  34. }
  35. failed_mail = Email.objects.create(status=STATUS.failed, **kwargs)
  36. none_mail = Email.objects.create(status=None, **kwargs)
  37. # This should be the only email that gets sent
  38. queued_mail = Email.objects.create(status=STATUS.queued, **kwargs)
  39. send_queued()
  40. self.assertNotEqual(Email.objects.get(id=failed_mail.id).status, STATUS.sent)
  41. self.assertNotEqual(Email.objects.get(id=none_mail.id).status, STATUS.sent)
  42. self.assertEqual(Email.objects.get(id=queued_mail.id).status, STATUS.sent)
  43. @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
  44. def test_send_queued_mail_multi_processes(self):
  45. """
  46. Check that send_queued works well with multiple processes
  47. """
  48. kwargs = {
  49. 'to': ['to@example.com'],
  50. 'from_email': 'bob@example.com',
  51. 'subject': 'Test',
  52. 'message': 'Message',
  53. 'status': STATUS.queued
  54. }
  55. # All three emails should be sent
  56. self.assertEqual(Email.objects.filter(status=STATUS.sent).count(), 0)
  57. for i in range(3):
  58. Email.objects.create(**kwargs)
  59. total_sent, total_failed = send_queued(processes=2)
  60. self.assertEqual(total_sent, 3)
  61. def test_send_bulk(self):
  62. """
  63. Ensure _send_bulk() properly sends out emails.
  64. """
  65. email = Email.objects.create(
  66. to=['to@example.com'], from_email='bob@example.com',
  67. subject='send bulk', message='Message', status=STATUS.queued,
  68. backend_alias='locmem')
  69. _send_bulk([email], uses_multiprocessing=False)
  70. self.assertEqual(Email.objects.get(id=email.id).status, STATUS.sent)
  71. self.assertEqual(len(mail.outbox), 1)
  72. self.assertEqual(mail.outbox[0].subject, 'send bulk')
  73. @override_settings(EMAIL_BACKEND='post_office.tests.test_mail.ConnectionTestingBackend')
  74. def test_send_bulk_reuses_open_connection(self):
  75. """
  76. Ensure _send_bulk() only opens connection once to send multiple emails.
  77. """
  78. global connection_counter
  79. self.assertEqual(connection_counter, 0)
  80. email = Email.objects.create(to=['to@example.com'],
  81. from_email='bob@example.com', subject='',
  82. message='', status=STATUS.queued, backend_alias='connection_tester')
  83. email_2 = Email.objects.create(to=['to@example.com'],
  84. from_email='bob@example.com', subject='',
  85. message='', status=STATUS.queued,
  86. backend_alias='connection_tester')
  87. _send_bulk([email, email_2])
  88. self.assertEqual(connection_counter, 1)
  89. def test_get_queued(self):
  90. """
  91. Ensure get_queued returns only emails that should be sent
  92. """
  93. kwargs = {
  94. 'to': 'to@example.com',
  95. 'from_email': 'bob@example.com',
  96. 'subject': 'Test',
  97. 'message': 'Message',
  98. }
  99. self.assertEqual(list(get_queued()), [])
  100. # Emails with statuses failed, sent or None shouldn't be returned
  101. Email.objects.create(status=STATUS.failed, **kwargs)
  102. Email.objects.create(status=None, **kwargs)
  103. Email.objects.create(status=STATUS.sent, **kwargs)
  104. self.assertEqual(list(get_queued()), [])
  105. # Email with queued status and None as scheduled_time should be included
  106. queued_email = Email.objects.create(status=STATUS.queued,
  107. scheduled_time=None, **kwargs)
  108. self.assertEqual(list(get_queued()), [queued_email])
  109. # Email scheduled for the future should not be included
  110. Email.objects.create(status=STATUS.queued,
  111. scheduled_time=date(2020, 12, 13), **kwargs)
  112. self.assertEqual(list(get_queued()), [queued_email])
  113. # Email scheduled in the past should be included
  114. past_email = Email.objects.create(status=STATUS.queued,
  115. scheduled_time=date(2010, 12, 13), **kwargs)
  116. self.assertEqual(list(get_queued()), [queued_email, past_email])
  117. def test_get_batch_size(self):
  118. """
  119. Ensure BATCH_SIZE setting is read correctly.
  120. """
  121. previous_settings = settings.POST_OFFICE
  122. self.assertEqual(get_batch_size(), 100)
  123. setattr(settings, 'POST_OFFICE', {'BATCH_SIZE': 10})
  124. self.assertEqual(get_batch_size(), 10)
  125. settings.POST_OFFICE = previous_settings
  126. def test_get_threads_per_process(self):
  127. """
  128. Ensure THREADS_PER_PROCESS setting is read correctly.
  129. """
  130. previous_settings = settings.POST_OFFICE
  131. self.assertEqual(get_threads_per_process(), 5)
  132. setattr(settings, 'POST_OFFICE', {'THREADS_PER_PROCESS': 10})
  133. self.assertEqual(get_threads_per_process(), 10)
  134. settings.POST_OFFICE = previous_settings
  135. def test_get_log_level(self):
  136. """
  137. Ensure LOG_LEVEL setting is read correctly.
  138. """
  139. previous_settings = settings.POST_OFFICE
  140. self.assertEqual(get_log_level(), 2)
  141. setattr(settings, 'POST_OFFICE', {'LOG_LEVEL': 1})
  142. self.assertEqual(get_log_level(), 1)
  143. # Restore ``LOG_LEVEL``
  144. setattr(settings, 'POST_OFFICE', {'LOG_LEVEL': 2})
  145. settings.POST_OFFICE = previous_settings
  146. def test_create(self):
  147. """
  148. Test basic email creation
  149. """
  150. # Test that email is persisted only when commit=True
  151. email = create(
  152. sender='from@example.com', recipients=['to@example.com'],
  153. commit=False
  154. )
  155. self.assertEqual(email.id, None)
  156. email = create(
  157. sender='from@example.com', recipients=['to@example.com'],
  158. commit=True
  159. )
  160. self.assertNotEqual(email.id, None)
  161. # Test that email is created with the right status
  162. email = create(
  163. sender='from@example.com', recipients=['to@example.com'],
  164. priority=PRIORITY.now
  165. )
  166. self.assertEqual(email.status, None)
  167. email = create(
  168. sender='from@example.com', recipients=['to@example.com'],
  169. priority=PRIORITY.high
  170. )
  171. self.assertEqual(email.status, STATUS.queued)
  172. # Test that email is created with the right content
  173. context = {
  174. 'subject': 'My subject',
  175. 'message': 'My message',
  176. 'html': 'My html',
  177. }
  178. now = datetime.now()
  179. email = create(
  180. sender='from@example.com', recipients=['to@example.com'],
  181. subject='Test {{ subject }}', message='Test {{ message }}',
  182. html_message='Test {{ html }}', context=context,
  183. scheduled_time=now, headers={'header': 'Test header'},
  184. )
  185. self.assertEqual(email.from_email, 'from@example.com')
  186. self.assertEqual(email.to, ['to@example.com'])
  187. self.assertEqual(email.subject, 'Test My subject')
  188. self.assertEqual(email.message, 'Test My message')
  189. self.assertEqual(email.html_message, 'Test My html')
  190. self.assertEqual(email.scheduled_time, now)
  191. self.assertEqual(email.headers, {'header': 'Test header'})
  192. def test_send_many(self):
  193. """Test send_many creates the right emails """
  194. kwargs_list = [
  195. {'sender': 'from@example.com', 'recipients': ['a@example.com']},
  196. {'sender': 'from@example.com', 'recipients': ['b@example.com']},
  197. ]
  198. send_many(kwargs_list)
  199. self.assertEqual(Email.objects.filter(to=['a@example.com']).count(), 1)
  200. def test_send_with_attachments(self):
  201. attachments = {
  202. 'attachment_file1.txt': ContentFile('content'),
  203. 'attachment_file2.txt': ContentFile('content'),
  204. }
  205. email = send(recipients=['a@example.com', 'b@example.com'],
  206. sender='from@example.com', message='message',
  207. subject='subject', attachments=attachments)
  208. self.assertTrue(email.pk)
  209. self.assertEqual(email.attachments.count(), 2)
  210. def test_send_with_render_on_delivery(self):
  211. """
  212. Ensure that mail.send() create email instances with appropriate
  213. fields being saved
  214. """
  215. template = EmailTemplate.objects.create(
  216. subject='Subject {{ name }}',
  217. content='Content {{ name }}',
  218. html_content='HTML {{ name }}'
  219. )
  220. context = {'name': 'test'}
  221. email = send(recipients=['a@example.com', 'b@example.com'],
  222. template=template, context=context,
  223. render_on_delivery=True)
  224. self.assertEqual(email.subject, '')
  225. self.assertEqual(email.message, '')
  226. self.assertEqual(email.html_message, '')
  227. self.assertEqual(email.template, template)
  228. # context shouldn't be persisted when render_on_delivery = False
  229. email = send(recipients=['a@example.com'],
  230. template=template, context=context,
  231. render_on_delivery=False)
  232. self.assertEqual(email.context, None)
  233. def test_send_with_attachments_multiple_recipients(self):
  234. """Test reusing the same attachment objects for several email objects"""
  235. attachments = {
  236. 'attachment_file1.txt': ContentFile('content'),
  237. 'attachment_file2.txt': ContentFile('content'),
  238. }
  239. email = send(recipients=['a@example.com', 'b@example.com'],
  240. sender='from@example.com', message='message',
  241. subject='subject', attachments=attachments)
  242. self.assertEqual(email.attachments.count(), 2)
  243. self.assertEqual(Attachment.objects.count(), 2)
  244. def test_create_with_template(self):
  245. """If render_on_delivery is True, subject and content
  246. won't be rendered, context also won't be saved."""
  247. template = EmailTemplate.objects.create(
  248. subject='Subject {{ name }}',
  249. content='Content {{ name }}',
  250. html_content='HTML {{ name }}'
  251. )
  252. context = {'name': 'test'}
  253. email = create(
  254. sender='from@example.com', recipients=['to@example.com'],
  255. template=template, context=context, render_on_delivery=True
  256. )
  257. self.assertEqual(email.subject, '')
  258. self.assertEqual(email.message, '')
  259. self.assertEqual(email.html_message, '')
  260. self.assertEqual(email.context, context)
  261. self.assertEqual(email.template, template)
  262. def test_create_with_template_and_empty_context(self):
  263. """If render_on_delivery is False, subject and content
  264. will be rendered, context won't be saved."""
  265. template = EmailTemplate.objects.create(
  266. subject='Subject {% now "Y" %}',
  267. content='Content {% now "Y" %}',
  268. html_content='HTML {% now "Y" %}'
  269. )
  270. context = None
  271. email = create(
  272. sender='from@example.com', recipients=['to@example.com'],
  273. template=template, context=context
  274. )
  275. today = date.today()
  276. current_year = today.year
  277. self.assertEqual(email.subject, 'Subject %d' % current_year)
  278. self.assertEqual(email.message, 'Content %d' % current_year)
  279. self.assertEqual(email.html_message, 'HTML %d' % current_year)
  280. self.assertEqual(email.context, None)
  281. self.assertEqual(email.template, None)
  282. def test_backend_alias(self):
  283. """Test backend_alias field is properly set."""
  284. email = send(recipients=['a@example.com'],
  285. sender='from@example.com', message='message',
  286. subject='subject')
  287. self.assertEqual(email.backend_alias, '')
  288. email = send(recipients=['a@example.com'],
  289. sender='from@example.com', message='message',
  290. subject='subject', backend='locmem')
  291. self.assertEqual(email.backend_alias, 'locmem')
  292. with self.assertRaises(ValueError):
  293. send(recipients=['a@example.com'], sender='from@example.com',
  294. message='message', subject='subject', backend='foo')
  295. @override_settings(LANGUAGES=(('en', 'English'), ('ru', 'Russian')))
  296. def test_send_with_template(self):
  297. """If render_on_delivery is False, subject and content
  298. will be rendered, context won't be saved."""
  299. template = EmailTemplate.objects.create(
  300. subject='Subject {{ name }}',
  301. content='Content {{ name }}',
  302. html_content='HTML {{ name }}'
  303. )
  304. russian_template = EmailTemplate(
  305. default_template=template,
  306. language='ru',
  307. subject='предмет {{ name }}',
  308. content='содержание {{ name }}',
  309. html_content='HTML {{ name }}'
  310. )
  311. russian_template.save()
  312. context = {'name': 'test'}
  313. email = send(recipients=['to@example.com'], sender='from@example.com',
  314. template=template, context=context)
  315. email = Email.objects.get(id=email.id)
  316. self.assertEqual(email.subject, 'Subject test')
  317. self.assertEqual(email.message, 'Content test')
  318. self.assertEqual(email.html_message, 'HTML test')
  319. self.assertEqual(email.context, None)
  320. self.assertEqual(email.template, None)
  321. # check, if we use the Russian version
  322. email = send(recipients=['to@example.com'], sender='from@example.com',
  323. template=russian_template, context=context)
  324. email = Email.objects.get(id=email.id)
  325. self.assertEqual(email.subject, 'предмет test')
  326. self.assertEqual(email.message, 'содержание test')
  327. self.assertEqual(email.html_message, 'HTML test')
  328. self.assertEqual(email.context, None)
  329. self.assertEqual(email.template, None)
  330. # Check that send picks template with the right language
  331. email = send(recipients=['to@example.com'], sender='from@example.com',
  332. template=template, context=context, language='ru')
  333. email = Email.objects.get(id=email.id)
  334. self.assertEqual(email.subject, 'предмет test')
  335. email = send(recipients=['to@example.com'], sender='from@example.com',
  336. template=template, context=context, language='ru',
  337. render_on_delivery=True)
  338. self.assertEqual(email.template.language, 'ru')
  339. def test_send_bulk_with_faulty_template(self):
  340. template = EmailTemplate.objects.create(
  341. subject='{% if foo %}Subject {{ name }}',
  342. content='Content {{ name }}',
  343. html_content='HTML {{ name }}'
  344. )
  345. email = Email.objects.create(to='to@example.com', from_email='from@example.com',
  346. template=template, status=STATUS.queued)
  347. _send_bulk([email], uses_multiprocessing=False)
  348. email = Email.objects.get(id=email.id)
  349. self.assertEqual(email.status, STATUS.failed)