docbow/tests/pfwb/test_pfwb.py

461 lines
18 KiB
Python

"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
import sys
import tempfile
from contextlib import contextmanager
from functools import wraps
from io import StringIO
from unittest import mock
from django.contrib.auth.models import User
from django.core import management
from django.test import TestCase
from django.test.utils import override_settings
from django.utils.encoding import force_bytes, force_str
from django_journal.models import Journal
from docbow_project.docbow.models import AttachedFile, Document, FileType, MailingList
from docbow_project.pfwb.models import PloneFileType, TabellioDocType
MEDIA_ROOT = tempfile.mkdtemp()
@contextmanager
def captured_output():
new_out, new_err = StringIO(), StringIO()
old_out, old_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = new_out, new_err
yield sys.stdout, sys.stderr
finally:
sys.stdout, sys.stderr = old_out, old_err
class stderr_output:
def __init__(self, output):
self.output = output
def __call__(self, func):
@wraps(func)
def f(testcase, *args, **kwargs):
with captured_output() as (out, err):
ret = func(testcase, *args, **kwargs)
testcase.assertEqual(self.output, err.getvalue())
return ret
return f
class stdout_output:
def __init__(self, output):
self.output = output
def __call__(self, func):
@wraps(func)
def f(testcase, *args, **kwargs):
with captured_output() as (out, err):
ret = func(testcase, *args, **kwargs)
testcase.assertEqual(self.output, out.getvalue())
return ret
return f
EXPEDITION_EMAIL = 'expedition@example.com'
RECIPIENT_EMAIL = 'recipient@example.com'
RECIPIENT_LIST_EMAIL = 'liste-ma-liste@example.com'
class MockUrlib:
def urlopen(self, url):
return self
def read(self):
with open('tests/data/django.pdf', 'rb') as f:
return f.read()
mockurllib = MockUrlib()
@override_settings(DOCBOW_PFWB_SENDMAIL_DEFAULT_TYPE_ID=1)
@override_settings(DOCBOW_PFWB_SENDMAIL_DEFAULT_TYPE_NAME='Default')
@override_settings(DOCBOW_PFWB_SENDMAIL_TABELLIO_EXPEDITION_EMAIL=EXPEDITION_EMAIL)
@override_settings(DOCBOW_PFWB_SENDMAIL_TABELLIO_EXPEDITION_USER_ID=1)
@override_settings(DOCBOW_PFWB_GED_DIRECTORY=None)
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
class SendMailTestCase(TestCase):
def setUp(self):
self.pjd_filetype = FileType.objects.create(name='PJD', id=2)
self.tabellio_doc_type = TabellioDocType.objects.create(
filetype=self.pjd_filetype, tabellio_doc_type='PJD'
)
self.expedition_user = User.objects.create(username='expedition', id=1)
self.to_user = User.objects.create(username='recipient', email=RECIPIENT_EMAIL, id=2)
self.to_list = MailingList.objects.create(name='ma liste')
self.to_list.members.add(self.to_user)
def send_tabellio_doc2(self, content, expedition_email, recipient_email, doc_type, subject):
content = content % {
'expedition_email': expedition_email,
'recipient_email': recipient_email,
'doc_type': doc_type,
'subject': subject,
}
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(content))
f.flush()
management.call_command('sendmail', recipient_email, file=f.name, sender=expedition_email)
def send_tabellio_doc(self, expedition_email, recipient_email, doc_type, subject):
content = '''\
Message-ID: <232323232@example.com>
From: %(expedition_email)s
To: %(recipient_email)s
Subject: %(subject)s
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.20 (2009-06-14)
X-Tabellio-Doc-Type: %(doc_type)s
X-Tabellio-Doc-URL: https://buildmedia.readthedocs.org/media/pdf/django/2.2.x/django.pdf
Status: RO
Coucou
'''
self.send_tabellio_doc2(content, expedition_email, recipient_email, doc_type, subject)
@stderr_output('7.7.1 No sender\n7.7.1 No sender\n')
def test_fail_sender(self):
with self.assertRaises(SystemExit):
management.call_command('sendmail', 'yyy')
with self.assertRaises(SystemExit):
management.call_command('sendmail', 'yyy', sender='')
@stderr_output('7.7.1 Mail is missing a Message-ID\n')
def test_fail_on_missing_message_id(self):
with self.assertRaises(SystemExit):
self.send_tabellio_doc2(
'''From: %(expedition_email)s
To: %(recipient_email)s
Subject: %(subject)s
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.20 (2009-06-14)
X-Tabellio-Doc-Type: %(doc_type)s
X-Tabellio-Doc-URL: https://buildmedia.readthedocs.org/media/pdf/django/2.2.x/django.pdf
Status: RO
Coucou''',
EXPEDITION_EMAIL,
RECIPIENT_EMAIL,
'PJD',
'Mouais: monfichier.pdf',
)
@stderr_output('7.7.1 Mail is missing a subject\n')
def test_fail_on_missing_subject(self):
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
with self.assertRaises(SystemExit):
self.send_tabellio_doc2(
'''From: %(expedition_email)s
Message-ID: <232323232@example.com>
To: %(recipient_email)s
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.20 (2009-06-14)
X-Tabellio-Doc-Type: %(doc_type)s
X-Tabellio-Doc-URL: https://buildmedia.readthedocs.org/media/pdf/django/2.2.x/django.pdf
Status: RO
Coucou''',
EXPEDITION_EMAIL,
RECIPIENT_EMAIL,
'PJD',
'Mouais: monfichier.pdf',
)
@stderr_output('7.7.1 Filename cannot be extracted from the subject\n')
def test_fail_on_missing_colon_in_subject(self):
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
with self.assertRaises(SystemExit):
self.send_tabellio_doc(EXPEDITION_EMAIL, RECIPIENT_EMAIL, 'PJD', 'Mouais')
@stderr_output(
"7.7.1 The email sent contains many errors:\n - Recipient 'xxx@xx.com' is not an user of the platform\n"
)
def test_fail_on_unknown_user(self):
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
with self.assertRaises(SystemExit):
self.send_tabellio_doc(EXPEDITION_EMAIL, 'xxx@xx.com', 'PJD', 'Mouais: monfichier.pdf')
@stderr_output('')
def test_fail_unknown_file_type(self):
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
self.assertEqual(FileType.objects.filter(name='Default').count(), 0)
self.send_tabellio_doc(EXPEDITION_EMAIL, RECIPIENT_EMAIL, 'XXX', 'Mouais: monfichier.pdf')
self.assertEqual(
Journal.objects.order_by('id')[0].message,
'unknown x-tabellio-doc-type XXX, using default filetype',
)
self.assertEqual(FileType.objects.filter(name='Default').count(), 1)
@stderr_output('')
def test_expedition_mode(self):
"""
Test sendmail management command when using the expedition mode
"""
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
self.send_tabellio_doc(EXPEDITION_EMAIL, RECIPIENT_EMAIL, 'PJD', 'Mouais: monfichier.pdf')
self.assertEqual(Document.objects.count(), 1)
assert Document.objects.get().to_user.count() == 1
assert Document.objects.get().to_list.count() == 0
@stderr_output('')
def test_get_user_by_email(self):
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
self.to_user.username = 'xyzfhtkre'
self.to_user.save()
self.send_tabellio_doc(EXPEDITION_EMAIL, RECIPIENT_EMAIL, 'PJD', 'Mouais: monfichier.pdf')
self.assertEqual(Document.objects.count(), 1)
assert Document.objects.get().to_user.count() == 1
assert Document.objects.get().to_list.count() == 0
@stderr_output('')
def test_expedition_mode_to_list(self):
"""
Test sendmail management command when using the expedition mode
"""
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
self.send_tabellio_doc(EXPEDITION_EMAIL, RECIPIENT_LIST_EMAIL, 'PJD', 'Mouais: monfichier.pdf')
self.assertEqual(Document.objects.count(), 1)
assert Document.objects.get().to_user.count() == 0
assert Document.objects.get().to_list.count() == 1
assert Document.objects.get().to_list.all()[0] == self.to_list
@override_settings(DOCBOW_PFWB_SENDMAIL_DEFAULT_TYPE_ID=1)
@override_settings(DOCBOW_PFWB_SENDMAIL_DEFAULT_TYPE_NAME='Default')
@override_settings(DOCBOW_PFWB_SENDMAIL_ATTACHED_FILE_EMAIL=EXPEDITION_EMAIL)
@override_settings(DOCBOW_PFWB_SENDMAIL_ATTACHED_FILE_USER_ID=1)
@override_settings(DOCBOW_PFWB_GED_DIRECTORY=None)
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
class SendMailAttachedFileTestCase(TestCase):
def setUp(self):
self.pjd_filetype = FileType.objects.create(name='PJD', id=2)
self.tabellio_doc_type = TabellioDocType.objects.create(
filetype=self.pjd_filetype, tabellio_doc_type='PJD'
)
self.expedition_user = User.objects.create(username='expedition', id=1)
self.to_user = User.objects.create(username='recipient', email=RECIPIENT_EMAIL, id=2)
self.to_list = MailingList.objects.create(name='ma liste')
self.to_list.members.add(self.to_user)
def build_message(self, filetype, to_addr, from_addr, content, attached_files):
import random
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
message = MIMEMultipart()
message['Subject'] = Header(force_str(filetype), 'utf-8')
message['To'] = Header(to_addr, 'utf-8')
message['From'] = Header(from_addr, 'utf-8')
message['Message-ID'] = '<%s@example.com>' % random.random()
msg = MIMEText(content, _subtype='plain')
message.attach(msg)
for filename, content in attached_files:
msg = MIMEBase('application', 'octet-stream')
msg.set_payload(content)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
encoders.encode_base64(msg)
message.attach(msg)
return force_bytes(message.as_string())
@stderr_output('')
def test_attached_file1(self):
with tempfile.NamedTemporaryFile() as f:
f.write(
self.build_message(
self.pjd_filetype,
EXPEDITION_EMAIL,
RECIPIENT_EMAIL,
'coucou',
(('attached-file', 'content'),),
)
)
f.flush()
management.call_command('sendmail', RECIPIENT_EMAIL, file=f.name, sender=EXPEDITION_EMAIL)
self.assertEqual(Document.objects.count(), 1)
document = Document.objects.get()
assert document.attached_files.count() == 1
assert document.comment == 'coucou'
assert document.attached_files.get().name == 'attached-file'
assert document.attached_files.get().content.read() == b'content'
assert document.to_user.count() == 1
assert document.to_list.count() == 0
assert document.to_user.get() == self.to_user
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
class PushDocumentTestCase(TestCase):
def setUp(self):
self.ged_dir = tempfile.mkdtemp()
def tearDown(self):
import shutil
shutil.rmtree(self.ged_dir)
def test_push_document1(self):
import os.path
from glob import glob
from django.core.files.base import ContentFile
with self.settings(DOCBOW_PFWB_GED_DIRECTORY=self.ged_dir):
FROM_USERNAME = 'from_user'
FROM_FIRST_NAME = 'from_first_name'
FROM_LAST_NAME = 'from_last_name'
self.from_user = User.objects.create(
username=FROM_USERNAME, first_name=FROM_FIRST_NAME, last_name=FROM_LAST_NAME
)
self.to_user = User.objects.create(username='to_user')
self.filetype = FileType.objects.create(name='filetype')
self.plone_filetype = PloneFileType.objects.create(
filetype=self.filetype, plone_portal_type='plone-portal-type'
)
DESCRIPTION = 'description'
self.document = Document.objects.create(
sender=self.from_user, filetype=self.filetype, comment=DESCRIPTION
)
self.attached_file = AttachedFile(name='attached-file', document=self.document, kind=None)
CONTENT = 'content'
self.attached_file.content.save('attached-file', ContentFile(CONTENT))
pattern1 = f'{self.document.id}-*-{self.attached_file.name}.json'
pattern2 = f'{self.document.id}-*-{self.attached_file.name}'
files1 = glob(os.path.join(self.ged_dir, pattern1))
files2 = glob(os.path.join(self.ged_dir, pattern2))
assert len(files1) == 1
assert len(files2) == 1
with open(files2[0]) as f:
assert f.read() == CONTENT
import json
with open(files1[0]) as f:
json_content = json.loads(f.read())
self.assertIsNotNone(json_content)
assert json_content['document_id'] == self.document.id
assert json_content['plone_portal_type'] == self.plone_filetype.plone_portal_type
assert json_content['title'] == force_str(self.filetype)
assert json_content['description'] == DESCRIPTION
assert json_content['sender'] == '{} {} ({})'.format(
FROM_FIRST_NAME, FROM_LAST_NAME, FROM_USERNAME
)
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
@override_settings(DOCBOW_PFWB_GED_DIRECTORY=None)
class ArchiveTestCase(TestCase):
def setUp(self):
from django.core.files.base import ContentFile
self.archive_dir = tempfile.mkdtemp()
FROM_USERNAME = 'from_user'
FROM_FIRST_NAME = 'from_first_name'
FROM_LAST_NAME = 'from_last_name'
self.from_user = User.objects.create(
username=FROM_USERNAME, first_name=FROM_FIRST_NAME, last_name=FROM_LAST_NAME
)
self.to_user = User.objects.create(username='to_user')
self.filetype = FileType.objects.create(name='filetype')
self.plone_filetype = PloneFileType.objects.create(
filetype=self.filetype, plone_portal_type='plone-portal-type'
)
DESCRIPTION = 'description'
self.document = Document.objects.create(
sender=self.from_user, filetype=self.filetype, comment=DESCRIPTION
)
self.attached_file = AttachedFile(name='attached-file', document=self.document, kind=None)
CONTENT = 'content'
self.attached_file.content.save('attached-file', ContentFile(CONTENT))
self.document.post()
def tearDown(self):
import shutil
shutil.rmtree(self.archive_dir)
def test_archive(self):
import datetime
import glob
import os.path
with captured_output() as (out, err):
management.call_command('archive2', self.archive_dir, 0)
file_list = glob.glob(os.path.join(self.archive_dir, '*'))
assert len(file_list) == 1
self.assertTrue(file_list[0].split('T')[0], datetime.datetime.today().isoformat())
archive_dir = os.path.join(self.archive_dir, file_list[0])
self.assertTrue(os.path.exists(os.path.join(archive_dir, 'doc')))
self.assertTrue(os.path.exists(os.path.join(archive_dir, 'doc', str(self.document.id))))
self.assertTrue(
os.path.exists(os.path.join(archive_dir, 'doc', str(self.document.id), 'document.json'))
)
self.assertTrue(
os.path.exists(
os.path.join(
archive_dir, 'doc', str(self.document.id), 'attached_file_%s.json' % self.attached_file.id
)
)
)
self.assertTrue(os.path.exists(os.path.join(archive_dir, 'journal.txt')))
def test_send_mail_truncate_filename(db, settings):
settings.DOCBOW_PFWB_SENDMAIL_TABELLIO_EXPEDITION_EMAIL = EXPEDITION_EMAIL
settings.DOCBOW_PFWB_SENDMAIL_TABELLIO_EXPEDITION_USER_ID = 1
settings.MEDIA_ROOT = MEDIA_ROOT
pjd_filetype = FileType.objects.create(name='PJD', id=2)
TabellioDocType.objects.create(filetype=pjd_filetype, tabellio_doc_type='PJD')
User.objects.create(username='expedition', id=1)
User.objects.create(username='recipient', email=RECIPIENT_EMAIL, id=2)
subject = 'foo: ' + 'aaaa M.' + 'b' * 300
content = '''\
Message-ID: <232323232@example.com>
From: %(expedition_email)s
To: %(recipient_email)s
Subject: foo: %(subject)s
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.20 (2009-06-14)
X-Tabellio-Doc-Type: %(doc_type)s
X-Tabellio-Doc-URL: https://buildmedia.readthedocs.org/media/pdf/django/2.2.x/django.pdf
Status: RO
Coucou
''' % {
'expedition_email': EXPEDITION_EMAIL,
'recipient_email': RECIPIENT_EMAIL,
'doc_type': 'PJD',
'subject': subject,
}
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(content))
f.flush()
with mock.patch('docbow_project.pfwb.management.commands.sendmail.urlopen', mockurllib.urlopen):
management.call_command('sendmail', RECIPIENT_EMAIL, file=f.name, sender=EXPEDITION_EMAIL)
assert Document.objects.count() == 1