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_models.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import django
  2. import json
  3. import os
  4. from datetime import datetime, timedelta
  5. from django.conf import settings as django_settings
  6. from django.core import mail
  7. from django.core import serializers
  8. from django.core.files.base import ContentFile
  9. from django.core.mail import EmailMessage, EmailMultiAlternatives
  10. from django.forms.models import modelform_factory
  11. from django.test import TestCase
  12. from django.utils import timezone
  13. from ..models import Email, Log, PRIORITY, STATUS, EmailTemplate, Attachment
  14. from ..mail import send
  15. class ModelTest(TestCase):
  16. def test_email_message(self):
  17. """
  18. Test to make sure that model's "email_message" method
  19. returns proper email classes.
  20. """
  21. # If ``html_message`` is set, ``EmailMultiAlternatives`` is expected
  22. email = Email.objects.create(to=['to@example.com'],
  23. from_email='from@example.com', subject='Subject',
  24. message='Message', html_message='<p>HTML</p>')
  25. message = email.email_message()
  26. self.assertEqual(type(message), EmailMultiAlternatives)
  27. self.assertEqual(message.from_email, 'from@example.com')
  28. self.assertEqual(message.to, ['to@example.com'])
  29. self.assertEqual(message.subject, 'Subject')
  30. self.assertEqual(message.body, 'Message')
  31. self.assertEqual(message.alternatives, [('<p>HTML</p>', 'text/html')])
  32. # Without ``html_message``, ``EmailMessage`` class is expected
  33. email = Email.objects.create(to=['to@example.com'],
  34. from_email='from@example.com', subject='Subject',
  35. message='Message')
  36. message = email.email_message()
  37. self.assertEqual(type(message), EmailMessage)
  38. self.assertEqual(message.from_email, 'from@example.com')
  39. self.assertEqual(message.to, ['to@example.com'])
  40. self.assertEqual(message.subject, 'Subject')
  41. self.assertEqual(message.body, 'Message')
  42. def test_email_message_render(self):
  43. """
  44. Ensure Email instance with template is properly rendered.
  45. """
  46. template = EmailTemplate.objects.create(
  47. subject='Subject {{ name }}',
  48. content='Content {{ name }}',
  49. html_content='HTML {{ name }}'
  50. )
  51. context = {'name': 'test'}
  52. email = Email.objects.create(to=['to@example.com'], template=template,
  53. from_email='from@e.com', context=context)
  54. message = email.email_message()
  55. self.assertEqual(message.subject, 'Subject test')
  56. self.assertEqual(message.body, 'Content test')
  57. self.assertEqual(message.alternatives[0][0], 'HTML test')
  58. def test_dispatch(self):
  59. """
  60. Ensure that email.dispatch() actually sends out the email
  61. """
  62. email = Email.objects.create(to=['to@example.com'], from_email='from@example.com',
  63. subject='Test dispatch', message='Message', backend_alias='locmem')
  64. email.dispatch()
  65. self.assertEqual(mail.outbox[0].subject, 'Test dispatch')
  66. def test_status_and_log(self):
  67. """
  68. Ensure that status and log are set properly on successful sending
  69. """
  70. email = Email.objects.create(to=['to@example.com'], from_email='from@example.com',
  71. subject='Test', message='Message', backend_alias='locmem', id=333)
  72. # Ensure that after dispatch status and logs are correctly set
  73. email.dispatch()
  74. log = Log.objects.latest('id')
  75. self.assertEqual(email.status, STATUS.sent)
  76. self.assertEqual(log.email, email)
  77. def test_status_and_log_on_error(self):
  78. """
  79. Ensure that status and log are set properly on sending failure
  80. """
  81. email = Email.objects.create(to=['to@example.com'], from_email='from@example.com',
  82. subject='Test', message='Message',
  83. backend_alias='error')
  84. # Ensure that after dispatch status and logs are correctly set
  85. email.dispatch()
  86. log = Log.objects.latest('id')
  87. self.assertEqual(email.status, STATUS.failed)
  88. self.assertEqual(log.email, email)
  89. self.assertEqual(log.status, STATUS.failed)
  90. self.assertEqual(log.message, 'Fake Error')
  91. self.assertEqual(log.exception_type, 'Exception')
  92. def test_errors_while_getting_connection_are_logged(self):
  93. """
  94. Ensure that status and log are set properly on sending failure
  95. """
  96. email = Email.objects.create(to=['to@example.com'], subject='Test',
  97. from_email='from@example.com',
  98. message='Message', backend_alias='random')
  99. # Ensure that after dispatch status and logs are correctly set
  100. email.dispatch()
  101. log = Log.objects.latest('id')
  102. self.assertEqual(email.status, STATUS.failed)
  103. self.assertEqual(log.email, email)
  104. self.assertEqual(log.status, STATUS.failed)
  105. self.assertIn('is not a valid', log.message)
  106. def test_default_sender(self):
  107. email = send(['to@example.com'], subject='foo')
  108. self.assertEqual(email.from_email,
  109. django_settings.DEFAULT_FROM_EMAIL)
  110. def test_send_argument_checking(self):
  111. """
  112. mail.send() should raise an Exception if:
  113. - "template" is used with "subject", "message" or "html_message"
  114. - recipients is not in tuple or list format
  115. """
  116. self.assertRaises(ValueError, send, ['to@example.com'], 'from@a.com',
  117. template='foo', subject='bar')
  118. self.assertRaises(ValueError, send, ['to@example.com'], 'from@a.com',
  119. template='foo', message='bar')
  120. self.assertRaises(ValueError, send, ['to@example.com'], 'from@a.com',
  121. template='foo', html_message='bar')
  122. self.assertRaises(ValueError, send, 'to@example.com', 'from@a.com',
  123. template='foo', html_message='bar')
  124. self.assertRaises(ValueError, send, cc='cc@example.com', sender='from@a.com',
  125. template='foo', html_message='bar')
  126. self.assertRaises(ValueError, send, bcc='bcc@example.com', sender='from@a.com',
  127. template='foo', html_message='bar')
  128. def test_send_with_template(self):
  129. """
  130. Ensure mail.send correctly creates templated emails to recipients
  131. """
  132. Email.objects.all().delete()
  133. headers = {'Reply-to': 'reply@email.com'}
  134. email_template = EmailTemplate.objects.create(name='foo', subject='bar',
  135. content='baz')
  136. scheduled_time = datetime.now() + timedelta(days=1)
  137. email = send(recipients=['to1@example.com', 'to2@example.com'], sender='from@a.com',
  138. headers=headers, template=email_template,
  139. scheduled_time=scheduled_time)
  140. self.assertEqual(email.to, ['to1@example.com', 'to2@example.com'])
  141. self.assertEqual(email.headers, headers)
  142. self.assertEqual(email.scheduled_time, scheduled_time)
  143. # Test without header
  144. Email.objects.all().delete()
  145. email = send(recipients=['to1@example.com', 'to2@example.com'], sender='from@a.com',
  146. template=email_template)
  147. self.assertEqual(email.to, ['to1@example.com', 'to2@example.com'])
  148. self.assertEqual(email.headers, None)
  149. def test_send_without_template(self):
  150. headers = {'Reply-to': 'reply@email.com'}
  151. scheduled_time = datetime.now() + timedelta(days=1)
  152. email = send(sender='from@a.com',
  153. recipients=['to1@example.com', 'to2@example.com'],
  154. cc=['cc1@example.com', 'cc2@example.com'],
  155. bcc=['bcc1@example.com', 'bcc2@example.com'],
  156. subject='foo', message='bar', html_message='baz',
  157. context={'name': 'Alice'}, headers=headers,
  158. scheduled_time=scheduled_time, priority=PRIORITY.low)
  159. self.assertEqual(email.to, ['to1@example.com', 'to2@example.com'])
  160. self.assertEqual(email.cc, ['cc1@example.com', 'cc2@example.com'])
  161. self.assertEqual(email.bcc, ['bcc1@example.com', 'bcc2@example.com'])
  162. self.assertEqual(email.subject, 'foo')
  163. self.assertEqual(email.message, 'bar')
  164. self.assertEqual(email.html_message, 'baz')
  165. self.assertEqual(email.headers, headers)
  166. self.assertEqual(email.priority, PRIORITY.low)
  167. self.assertEqual(email.scheduled_time, scheduled_time)
  168. # Same thing, but now with context
  169. email = send(['to1@example.com'], 'from@a.com',
  170. subject='Hi {{ name }}', message='Message {{ name }}',
  171. html_message='<b>{{ name }}</b>',
  172. context={'name': 'Bob'}, headers=headers)
  173. self.assertEqual(email.to, ['to1@example.com'])
  174. self.assertEqual(email.subject, 'Hi Bob')
  175. self.assertEqual(email.message, 'Message Bob')
  176. self.assertEqual(email.html_message, '<b>Bob</b>')
  177. self.assertEqual(email.headers, headers)
  178. def test_invalid_syntax(self):
  179. """
  180. Ensures that invalid template syntax will result in validation errors
  181. when saving a ModelForm of an EmailTemplate.
  182. """
  183. data = dict(
  184. name='cost',
  185. subject='Hi there!{{ }}',
  186. content='Welcome {{ name|titl }} to the site.',
  187. html_content='{% block content %}<h1>Welcome to the site</h1>'
  188. )
  189. EmailTemplateForm = modelform_factory(EmailTemplate,
  190. exclude=['template'])
  191. form = EmailTemplateForm(data)
  192. self.assertFalse(form.is_valid())
  193. self.assertEqual(form.errors['default_template'], [u'This field is required.'])
  194. self.assertEqual(form.errors['content'], [u"Invalid filter: 'titl'"])
  195. self.assertIn(form.errors['html_content'],
  196. [[u'Unclosed tags: endblock '],
  197. [u"Unclosed tag on line 1: 'block'. Looking for one of: endblock."]])
  198. self.assertIn(form.errors['subject'],
  199. [[u'Empty variable tag'], [u'Empty variable tag on line 1']])
  200. def test_string_priority(self):
  201. """
  202. Regression test for:
  203. https://github.com/ui/django-post_office/issues/23
  204. """
  205. email = send(['to1@example.com'], 'from@a.com', priority='low')
  206. self.assertEqual(email.priority, PRIORITY.low)
  207. def test_default_priority(self):
  208. email = send(recipients=['to1@example.com'], sender='from@a.com')
  209. self.assertEqual(email.priority, PRIORITY.medium)
  210. def test_string_priority_exception(self):
  211. invalid_priority_send = lambda: send(['to1@example.com'], 'from@a.com', priority='hgh')
  212. with self.assertRaises(ValueError) as context:
  213. invalid_priority_send()
  214. self.assertEqual(
  215. str(context.exception),
  216. 'Invalid priority, must be one of: low, medium, high, now'
  217. )
  218. def test_send_recipient_display_name(self):
  219. """
  220. Regression test for:
  221. https://github.com/ui/django-post_office/issues/73
  222. """
  223. email = send(recipients=['Alice Bob <email@example.com>'], sender='from@a.com')
  224. self.assertTrue(email.to)
  225. def test_attachment_filename(self):
  226. attachment = Attachment()
  227. attachment.file.save(
  228. 'test.txt',
  229. content=ContentFile('test file content'),
  230. save=True
  231. )
  232. self.assertEqual(attachment.name, 'test.txt')
  233. # Test that it is saved to the correct subdirectory
  234. date = timezone.now().date()
  235. expected_path = os.path.join('post_office_attachments', str(date.year),
  236. str(date.month), str(date.day))
  237. self.assertTrue(expected_path in attachment.file.name)
  238. def test_attachments_email_message(self):
  239. email = Email.objects.create(to=['to@example.com'],
  240. from_email='from@example.com',
  241. subject='Subject')
  242. attachment = Attachment()
  243. attachment.file.save(
  244. 'test.txt', content=ContentFile('test file content'), save=True
  245. )
  246. email.attachments.add(attachment)
  247. message = email.email_message()
  248. # https://docs.djangoproject.com/en/1.11/releases/1.11/#email
  249. if django.VERSION >= (1, 11,):
  250. self.assertEqual(message.attachments,
  251. [('test.txt', 'test file content', 'text/plain')])
  252. else:
  253. self.assertEqual(message.attachments,
  254. [('test.txt', b'test file content', None)])
  255. def test_attachments_email_message_with_mimetype(self):
  256. email = Email.objects.create(to=['to@example.com'],
  257. from_email='from@example.com',
  258. subject='Subject')
  259. attachment = Attachment()
  260. attachment.file.save(
  261. 'test.txt', content=ContentFile('test file content'), save=True
  262. )
  263. attachment.mimetype = 'text/plain'
  264. attachment.save()
  265. email.attachments.add(attachment)
  266. message = email.email_message()
  267. if django.VERSION >= (1, 11,):
  268. self.assertEqual(message.attachments,
  269. [('test.txt', 'test file content', 'text/plain')])
  270. else:
  271. self.assertEqual(message.attachments,
  272. [('test.txt', b'test file content', 'text/plain')])
  273. def test_translated_template_uses_default_templates_name(self):
  274. template = EmailTemplate.objects.create(name='name')
  275. id_template = template.translated_templates.create(language='id')
  276. self.assertEqual(id_template.name, template.name)
  277. def test_models_repr(self):
  278. self.assertEqual(repr(EmailTemplate(name='test', language='en')),
  279. '<EmailTemplate: test en>')
  280. self.assertEqual(repr(Email(to=['test@example.com'])),
  281. "<Email: ['test@example.com']>")
  282. def test_natural_key(self):
  283. template = EmailTemplate.objects.create(name='name')
  284. self.assertEqual(template, EmailTemplate.objects.get_by_natural_key(*template.natural_key()))
  285. data = serializers.serialize('json', [template], use_natural_primary_keys=True)
  286. self.assertNotIn('pk', json.loads(data)[0])
  287. deserialized_objects = serializers.deserialize('json', data, use_natural_primary_keys=True)
  288. list(deserialized_objects)[0].save()
  289. self.assertEqual(EmailTemplate.objects.count(), 1)