This repository has been archived on 2026-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
RepApp/repapp/email_interface/tests.py

840 lines
26 KiB
Python
Raw Normal View History

2023-09-02 15:09:21 +00:00
import os
2023-08-31 13:21:38 +00:00
import logging
2023-09-02 15:09:21 +00:00
from pathlib import Path
from unittest.mock import patch
from django.test import TestCase, Client
2023-08-31 16:44:17 +00:00
from django.conf import settings
2023-09-02 15:09:21 +00:00
from django.test.client import RequestFactory
2023-08-31 13:21:38 +00:00
from django.contrib.auth import get_user_model
2023-09-02 15:09:21 +00:00
from django.core import mail
from django.utils import translation
from django.urls import reverse
2023-08-31 13:21:38 +00:00
from .forms import MessageForm
2023-08-31 16:44:17 +00:00
from .models import Message, Attachment
2023-09-02 15:09:21 +00:00
from .utils import create_message, send_message, process_message
from one_time_login.utils import create_one_time_login
2023-08-30 19:19:36 +00:00
2023-08-31 13:21:38 +00:00
logger = logging.getLogger(__name__)
class MessageFormTestCase(TestCase):
"""
Tests all logic contained in the OneTimeLogin model.
"""
def setUp(self):
user = get_user_model().objects.create_user(
"john",
"lennon@thebeatles.com",
"johnpassword")
user.save()
def test_message_from_ok_no_text(self):
user = get_user_model().objects.get(username='john')
form = MessageForm({
'receiver': user.pk,
'summary': 'My mail summary',
'html_content': '<p>Hallo, Welt!</p>',
'mail_text': '',
'use_mail_text': False,
})
assert form.is_valid(), 'form is valid'
message = form.save(commit=False)
logger.debug('Message: %s', message)
logger.debug('Message text: %s', message.text_content)
assert message.pk is None, 'message was not saved'
assert message.receiver == user, 'receiver is set'
assert message.sender is None, 'no sender is set'
assert message.summary == 'My mail summary', 'summary is set'
assert message.html_content == '<p>Hallo, Welt!</p>', 'HTML is set'
assert 'Hallo, Welt!' in message.text_content, 'text was generated'
message = form.save()
assert message.pk is not None, 'message was saved'
def test_message_from_ok_text(self):
user = get_user_model().objects.get(username='john')
form = MessageForm({
'receiver': user.pk,
'summary': 'My mail summary',
'html_content': '<p>Hallo, Welt!</p>',
'mail_text': 'Hallo!',
'use_mail_text': True,
})
assert form.is_valid(), 'form is valid'
message = form.save(commit=False)
logger.debug('Message: %s', message)
logger.debug('Message text: %s', message.text_content)
assert message.pk is None, 'message was not saved'
assert message.receiver == user, 'receiver is set'
assert message.sender is None, 'no sender is set'
assert message.summary == 'My mail summary', 'summary is set'
assert message.html_content == '<p>Hallo, Welt!</p>', 'HTML is set'
assert message.text_content == 'Hallo!', 'text was used'
def test_message_from_wrong_no_text(self):
user = get_user_model().objects.get(username='john')
form = MessageForm({
'receiver': user.pk,
'summary': 'My mail summary',
'html_content': '<p>Hallo, Welt!</p>',
'mail_text': '',
'use_mail_text': True,
})
logger.debug('Form data: text: %r', form)
assert not form.is_valid()
assert form.has_error('mail_text')
2023-08-31 16:44:17 +00:00
class MessageModelTestCase(TestCase):
"""
Tests all logic contained in the Message model.
"""
def setUp(self):
john = get_user_model().objects.create_user(
"john",
"lennon@thebeatles.com",
"johnpassword")
john.save()
self.john = john
jane = get_user_model().objects.create_user(
"jane",
"doe@example.com",
"janepassword")
jane.save()
self.jane = jane
m1 = Message(
summary='summary 1',
html_content='<p>mail 1 HTML content</p>',
text_content='mail 1 text content',
sender=john,
receiver=jane,
sent=True,
answered=True,
)
m1.save()
self.m1 = m1
m2 = Message(
summary='summary 2',
html_content='<p>mail 2 HTML content</p>',
text_content='mail 2 text content',
sender=jane,
receiver=john,
sent=True,
answered=False,
reply_to=m1,
)
m2.save()
self.m2 = m2
m3 = Message(
summary='summary 3',
html_content='<p>mail 3 HTML content</p>',
text_content='mail 3 text content',
sender=jane,
receiver=john,
sent=True,
answered=False,
reply_to=m1,
)
m3.save()
self.m3 = m3
a1 = Attachment(
owner=john,
name='johns_file.txt',
mime_type='text/plain',
file='uploads/johns_file.txt',
message=m1,
)
a1.save()
self.a1 = a1
a2 = Attachment(
owner=jane,
name='janes_image.jpg',
mime_type='image/jpeg',
file='media/janes_image.jpg',
message=m3,
)
a2.save()
self.a2 = a2
a3 = Attachment(
owner=john,
name='johns_image.jpg',
mime_type='image/png',
file='media/johns_image.jpg',
message=m1,
)
a3.save()
self.a3 = a3
def test_str(self):
assert self.m1.summary in str(self.m1)
assert str(self.m1.receiver) in str(self.m1)
def test_attachments(self):
assert len(self.m1.attachments()) == 2
assert self.m1.attachments()[0].pk == self.a1.pk
assert self.m1.attachments()[1].pk == self.a3.pk
assert len(self.m2.attachments()) == 0
assert len(self.m3.attachments()) == 1
assert self.m3.attachments()[0].pk == self.a2.pk
def test_thread(self):
assert len(self.m1.thread()) == 1
assert self.m1.thread()[0].pk == self.m1.pk
assert len(self.m2.thread()) == 2
assert self.m2.thread()[0].pk == self.m1.pk
assert self.m2.thread()[1].pk == self.m2.pk
assert len(self.m3.thread()) == 2
assert self.m3.thread()[0].pk == self.m1.pk
assert self.m3.thread()[1].pk == self.m3.pk
def test_answers(self):
assert len(self.m1.answers()) == 2
assert self.m1.answers()[0].pk == self.m2.pk
assert self.m1.answers()[1].pk == self.m3.pk
assert len(self.m2.answers()) == 0
assert len(self.m3.answers()) == 0
def test_siblings(self):
assert len(self.m1.siblings()) == 0
assert len(self.m2.siblings()) == 1
assert self.m2.siblings()[0].pk == self.m3.pk
assert len(self.m3.siblings()) == 1
assert self.m3.siblings()[0].pk == self.m2.pk
def test_to_user(self):
assert len(Message.to_user(self.john)) == 2
assert Message.to_user(self.john)[0].pk == self.m2.pk
assert Message.to_user(self.john)[1].pk == self.m3.pk
assert len(Message.to_user(self.jane)) == 1
assert Message.to_user(self.jane)[0].pk == self.m1.pk
def test_from_user(self):
assert len(Message.from_user(self.john)) == 1
assert Message.from_user(self.john)[0].pk == self.m1.pk
assert len(Message.from_user(self.jane)) == 2
assert Message.from_user(self.jane)[0].pk == self.m2.pk
assert Message.from_user(self.jane)[1].pk == self.m3.pk
class AttachmentModelTestCase(TestCase):
"""
2023-09-02 15:09:21 +00:00
Tests all logic contained in the Attachment model.
2023-08-31 16:44:17 +00:00
"""
def setUp(self):
john = get_user_model().objects.create_user(
"john",
"lennon@thebeatles.com",
"johnpassword")
john.save()
self.john = john
jane = get_user_model().objects.create_user(
"jane",
"doe@example.com",
"janepassword")
jane.save()
self.jane = jane
m1 = Message(
summary='summary 1',
html_content='<p>mail 1 HTML content</p>',
text_content='mail 1 text content',
sender=john,
receiver=jane,
sent=True,
answered=True,
)
m1.save()
self.m1 = m1
m3 = Message(
summary='summary 3',
html_content='<p>mail 3 HTML content</p>',
text_content='mail 3 text content',
sender=jane,
receiver=john,
sent=True,
answered=False,
reply_to=m1,
)
m3.save()
self.m3 = m3
a1 = Attachment(
owner=john,
name='johns_file.txt',
mime_type='text/plain',
file='uploads/johns_file.txt',
message=m1,
)
a1.save()
self.a1 = a1
a2 = Attachment(
owner=jane,
name='janes_image.jpg',
mime_type='image/jpeg',
file='media/janes_image.jpg',
message=m3,
)
a2.save()
self.a2 = a2
a3 = Attachment(
owner=john,
name='johns_image.jpg',
mime_type='image/png',
file='media/johns_image.jpg',
message=m1,
)
a3.save()
self.a3 = a3
def test_str(self):
assert str(self.a1.file) in str(self.a1)
assert str(self.m1) in str(self.a1)
def test_get_absolute_url(self):
assert settings.MEDIA_URL in self.a1.get_absolute_url()
assert str(self.a1.file) in self.a1.get_absolute_url()
def test_of_user(self):
assert len(Attachment.of_user(self.john)) == 2
assert Attachment.of_user(self.john)[0].pk == self.a1.pk
assert Attachment.of_user(self.john)[1].pk == self.a3.pk
assert len(Attachment.of_user(self.jane)) == 1
assert Attachment.of_user(self.jane)[0].pk == self.a2.pk
2023-09-02 15:09:21 +00:00
class UtilsTestCase(TestCase):
"""
Tests all logic contained in utils.
"""
def setUp(self):
# prepare request factory
self.factory = RequestFactory()
# prepare test data
john = get_user_model().objects.create_user(
"john",
"lennon@thebeatles.com",
"johnpassword")
john.save()
self.john = john
jane = get_user_model().objects.create_user(
"jane",
"doe@example.com",
"janepassword")
jane.save()
self.jane = jane
m1 = Message(
summary='summary 1',
html_content='<p>mail 1 HTML content</p>',
text_content='mail 1 text content',
sender=john,
receiver=jane,
sent=True,
answered=True,
)
m1.save()
self.m1 = m1
self.attachment_file = os.path.join(
Path(__file__).resolve().parent, 'test_data', 'Nut.jpg')
def test_create_message(self):
request = self.factory.get('/')
sent = create_message(
request=request,
sender=self.john,
receiver=self.jane,
summary='A test message',
html_content='<p>Test HTML content</p>',
text_content='Test text content',
attachments=[self.attachment_file, '/does-not-exist'],
reply_to=self.m1,
send=False
)
assert not sent
assert len(mail.outbox) == 0
message = Message.objects.filter(summary='A test message').first()
assert message.sender == self.john
assert message.receiver == self.jane
assert message.html_content == '<p>Test HTML content</p>'
assert message.text_content == 'Test text content'
assert message.reply_to == self.m1
attachments = message.attachments()
assert len(attachments) == 1
assert 'Nut' in str(attachments[0].name)
assert 'Nut' in str(attachments[0].file)
assert 'image/jpeg' == attachments[0].mime_type
assert attachments[0].owner == self.john
assert attachments[0].message == message
path = attachments[0].file.path
logger.debug('Attachment file: %s', attachments[0].file.path)
assert os.path.isfile(path)
message.delete()
# deleting the message should also delete the attachment and the file
assert not os.path.isfile(path)
def test_send_message(self):
request = self.factory.get('/')
create_message(
request=request,
sender=self.john,
receiver=self.jane,
summary='Another test message',
html_content=f'<img src="{settings.MEDIA_URL}/image.jpg">',
text_content='Test text content',
attachments=[self.attachment_file, '/does-not-exist'],
reply_to=self.m1,
send=False
)
message = Message.objects.filter(
summary='Another test message').first()
sent = send_message(message=message, request=request)
assert sent
assert len(mail.outbox) == 1
m = mail.outbox[0]
assert len(m.recipients()) == 1
assert self.jane.email in m.recipients()
logger.debug('Mail sender: %r', m.from_email)
assert m.from_email == settings.DEFAULT_FROM_EMAIL
assert m.body == 'Test text content'
logger.debug('Mail attachments: %r', len(m.attachments))
assert 'Nut' in str(m.attachments[0])
assert 'image/jpeg' in str(m.attachments[0])
absolute_media_url = request.build_absolute_uri(settings.MEDIA_URL)
assert absolute_media_url in m.message().as_string()
message.delete()
def test_create_message_and_send(self):
request = self.factory.get('/')
sent = create_message(
request=request,
sender=self.john,
receiver=self.jane,
summary='My test message',
html_content='<p>Test HTML content</p>',
text_content='Test text content',
attachments=[self.attachment_file, '/does-not-exist'],
reply_to=self.m1,
send=True
)
assert sent
assert len(mail.outbox) == 1
message = Message.objects.filter(summary='My test message').first()
message.delete()
def test_process_message_no_guest(self):
with patch('imap_tools.MailMessage') as MockClass:
mock = MockClass.return_value
mock.from_ = 'noguest@example.com'
mock.subject = 'subject'
processed = process_message(mock)
assert not processed
def test_process_message_reply(self):
with patch('imap_tools.MailMessage') as MockClass:
mock = MockClass.return_value
mock.from_ = self.m1.receiver.email
mock.subject = f'Re: {self.m1.summary}'
mock.html = '<p>HTML content</p>'
mock.text = 'Text content'
mock.attachments = []
processed = process_message(mock)
assert processed
assert self.m1.answered
message = Message.objects.filter(summary=mock.subject).first()
assert message.reply_to == self.m1
assert message.sender == self.m1.receiver
assert message.receiver == self.m1.sender
assert message.summary == f'Re: {self.m1.summary}'
assert message.html_content == '<p>HTML content</p>'
assert message.text_content == 'Text content'
def test_process_message_new_message(self):
with patch('imap_tools.MailMessage') as MockClass:
mock = MockClass.return_value
mock.from_ = self.m1.receiver.email
mock.subject = 'New message'
mock.html = '<p>HTML content</p>'
mock.text = 'Text content'
mock.attachments = []
processed = process_message(mock)
assert processed
message = Message.objects.filter(summary=mock.subject).first()
assert message.reply_to == None
assert message.sender == self.m1.receiver
assert message.receiver == None
assert message.summary == 'New message'
assert message.html_content == '<p>HTML content</p>'
assert message.text_content == 'Text content'
def test_process_message_attachments(self):
with patch('imap_tools.MailMessage') as MockClass:
with patch('imap_tools.MailAttachment') as MockAttachmentClass:
with open(self.attachment_file, "rb") as file:
mock = MockClass.return_value
attachment_mock = MockAttachmentClass.return_value
attachment_mock.filename = 'test.jpg'
attachment_mock.content_type = 'image/jpeg'
attachment_mock.payload = file.read()
mock.from_ = self.m1.receiver.email
mock.subject = 'New message with attachment'
mock.html = '<p>HTML content</p>'
mock.text = 'Text content'
mock.attachments = [attachment_mock]
processed = process_message(mock)
assert processed
message = Message.objects.filter(
summary=mock.subject).first()
assert message.reply_to == None
assert message.sender == self.m1.receiver
assert message.receiver == None
assert message.summary == 'New message with attachment'
assert message.html_content == '<p>HTML content</p>'
assert message.text_content == 'Text content'
attachment = Attachment.objects.filter(
message=message).first()
logger.debug('Attachment: %r', attachment)
assert attachment.owner == self.m1.receiver
assert 'test' in attachment.name
assert attachment.mime_type == 'image/jpeg'
assert 'test' in attachment.file.path
assert os.path.isfile(attachment.file.path)
message.delete()
# deleting the message should also delete the attachment and the file
assert not os.path.isfile(attachment.file.path)
class ViewsTestCase(TestCase):
"""
Test email interface views.
"""
def setUp(self):
# use english translations
translation.activate('en')
# prepare test data
john = get_user_model().objects.create_user(
"john",
"lennon@thebeatles.com",
"johnpassword")
john.save()
self.john = john
jane = get_user_model().objects.create_user(
"jane",
"doe@example.com",
"janepassword")
jane.save()
self.jane = jane
m1 = Message(
summary='summary 1',
html_content='<p>mail 1 HTML content</p>',
text_content='mail 1 text content',
sender=john,
receiver=jane,
sent=True,
answered=True,
)
m1.save()
self.m1 = m1
m3 = Message(
summary='summary 3',
html_content='<p>mail 3 HTML content</p>',
text_content='mail 3 text content',
sender=jane,
receiver=john,
sent=True,
answered=False,
reply_to=m1,
)
m3.save()
self.m3 = m3
a1 = Attachment(
owner=john,
name='johns_file.txt',
mime_type='text/plain',
file='uploads/johns_file.txt',
message=m1,
)
a1.save()
self.a1 = a1
a2 = Attachment(
owner=jane,
name='janes_image.jpg',
mime_type='image/jpeg',
file='media/janes_image.jpg',
message=m3,
)
a2.save()
self.a2 = a2
a3 = Attachment(
owner=john,
name='johns_image.jpg',
mime_type='image/png',
file='media/johns_image.jpg',
message=m1,
)
a3.save()
self.a3 = a3
def test_my_attachments_is_protected(self):
url = reverse('email_interface:my_attachments')
client = Client()
response = client.get(url, follow=True)
logger.debug('test_my_attachments_is_protected: %r',
response.redirect_chain[-1])
last_url, status_code = response.redirect_chain[-1]
assert status_code == 302
assert last_url == '/accounts/login/?next=/en/emails/attachments/'
def test_my_attachments(self):
user = get_user_model().objects.get(username='john')
url = reverse('email_interface:my_attachments')
otl = create_one_time_login(user, url)
client = Client()
response = client.get(otl.get_absolute_url(), follow=True)
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
self.assertContains(response, 'johns_file.txt')
self.assertContains(response, 'johns_image.jpg')
self.assertNotContains(response, 'janes_image')
def test_my_received_mails_is_protected(self):
url = reverse('email_interface:my_received_mails')
client = Client()
response = client.get(url, follow=True)
logger.debug('test_my_received_mails_is_protected: %r',
response.redirect_chain[-1])
last_url, status_code = response.redirect_chain[-1]
assert status_code == 302
assert last_url == '/accounts/login/?next=/en/emails/received/'
def test_my_received_mails(self):
user = get_user_model().objects.get(username='john')
url = reverse('email_interface:my_received_mails')
otl = create_one_time_login(user, url)
client = Client()
response = client.get(otl.get_absolute_url(), follow=True)
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
self.assertContains(response, '<p>mail 3 HTML content</p>')
self.assertContains(response, 'janes_image')
self.assertNotContains(response, '<p>mail 1 HTML content</p>')
def test_my_sent_mails_is_protected(self):
url = reverse('email_interface:my_sent_mails')
client = Client()
response = client.get(url, follow=True)
logger.debug('test_my_sent_mails_is_protected: %r',
response.redirect_chain[-1])
last_url, status_code = response.redirect_chain[-1]
assert status_code == 302
assert last_url == '/accounts/login/?next=/en/emails/sent/'
def test_my_sent_mails(self):
user = get_user_model().objects.get(username='john')
url = reverse('email_interface:my_sent_mails')
otl = create_one_time_login(user, url)
client = Client()
response = client.get(otl.get_absolute_url(), follow=True)
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
self.assertContains(response, '<p>mail 1 HTML content</p>')
self.assertNotContains(response, '<p>mail 3 HTML content</p>')
def test_mail_thread_is_protected(self):
url = reverse('email_interface:mail_thread', kwargs={'id': self.m3.pk})
client = Client()
response = client.get(url, follow=True)
logger.debug('test_my_received_mails_is_protected: %r',
response.redirect_chain[-1])
last_url, status_code = response.redirect_chain[-1]
assert status_code == 302
assert last_url == f'/accounts/login/?next=/en/emails/{self.m3.pk}/view/'
def test_mail_thread(self):
user = get_user_model().objects.get(username='john')
url = reverse('email_interface:mail_thread', kwargs={'id': self.m3.pk})
otl = create_one_time_login(user, url)
client = Client()
response = client.get(otl.get_absolute_url(), follow=True)
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
self.assertContains(response, '<p>mail 3 HTML content</p>')
self.assertContains(response, 'janes_image')
self.assertContains(response, '<p>mail 1 HTML content</p>')
def test_mail_thread_reply(self):
user = get_user_model().objects.get(username='john')
url = reverse('email_interface:mail_thread', kwargs={'id': self.m3.pk})
otl = create_one_time_login(user, url)
client = Client()
response = client.get(otl.get_absolute_url(), follow=True)
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
response = client.post(url, {
'html_content': '<p>The reply content.</p>',
'receiver': self.jane.pk,
'use_mail_text': '',
'mail_text': '',
}, follow=True)
logger.debug('Post response: %r', response)
message = Message.objects.filter(reply_to=self.m3).first()
url = reverse('email_interface:mail_thread', kwargs={'id': message.pk})
assert response.status_code == 200, 'response is OK'
last_url, _ = response.redirect_chain[-1]
assert last_url == url, 'redirect URL'
self.assertContains(response, 'Mail was sent.')
assert len(mail.outbox) == 1
logger.debug('Outbox: %r', mail.outbox[0].subject)
assert mail.outbox[0].subject == 'Re: summary 3'
assert self.jane.email in mail.outbox[0].recipients()
assert message.reply_to == self.m3
assert message.sender == user
assert message.receiver == self.jane
assert message.summary == 'Re: summary 3'
assert message.html_content == '<p>The reply content.</p>'
assert 'The reply content.' in message.text_content