docbow/tests/pfwb/test_pfwb.py

464 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.
"""
from io import StringIO
import tempfile
import sys
from contextlib import contextmanager
from functools import wraps
from django.utils.encoding import force_bytes, force_text
import mock
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(object):
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(object):
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
from django.test import TestCase
from django.test.utils import override_settings
from django.core import management
from django.contrib.auth.models import User
from docbow_project.pfwb.models import TabellioDocType, PloneFileType
from docbow_project.docbow.models import FileType, MailingList, Document, AttachedFile
from django_journal.models import Journal
EXPEDITION_EMAIL = 'expedition@example.com'
RECIPIENT_EMAIL = 'recipient@example.com'
RECIPIENT_LIST_EMAIL = 'liste-ma-liste@example.com'
class MockUrlib(object):
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):
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
import random
message = MIMEMultipart()
message['Subject'] = Header(force_text(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):
from django.core.files.base import ContentFile
import os.path
from glob import glob
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 = '{0}-*-{1}.json'.format(self.document.id, self.attached_file.name)
pattern2 = '{0}-*-{1}'.format(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_text(self.filetype)
assert json_content['description'] == DESCRIPTION
assert json_content['sender'] == u'{0} {1} ({2})'.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 os.path
import glob
import datetime
with captured_output() as (out, err):
management.call_command('archive2', self.archive_dir, 0)
l = glob.glob(os.path.join(self.archive_dir, '*'))
assert len(l) == 1
self.assertTrue(l[0].split('T')[0], datetime.datetime.today().isoformat())
archive_dir = os.path.join(self.archive_dir, l[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)
tabellio_doc_type = TabellioDocType.objects.create(filetype=pjd_filetype, tabellio_doc_type='PJD')
expedition_user = User.objects.create(username='expedition', id=1)
to_user = 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