source: main/waeup.sirp/trunk/src/waeup/sirp/tests/test_smtp.py @ 7474

Last change on this file since 7474 was 7474, checked in by uli, 13 years ago

pyflakes.

File size: 13.3 KB
RevLine 
[7470]1# -*- coding: utf-8 -*-
2##
3## test_smtp.py
4## Login : <uli@pu.smp.net>
5## Started on  Wed Dec 21 15:08:50 2011 Uli Fouquet
6## $Id$
7##
8## Copyright (C) 2011 Uli Fouquet
9## This program is free software; you can redistribute it and/or modify
10## it under the terms of the GNU General Public License as published by
11## the Free Software Foundation; either version 2 of the License, or
12## (at your option) any later version.
13##
14## This program is distributed in the hope that it will be useful,
15## but WITHOUT ANY WARRANTY; without even the implied warranty of
16## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17## GNU General Public License for more details.
18##
19## You should have received a copy of the GNU General Public License
20## along with this program; if not, write to the Free Software
21## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22##
23# Tests for email-related components
24import base64
25import logging
26import tempfile
27import shutil
28import unittest
29from StringIO import StringIO
30from zope.component import getUtility
[7474]31from zope.component.hooks import setSite
[7470]32from zope.sendmail.interfaces import IMailDelivery
33from waeup.sirp.app import University
[7473]34from waeup.sirp.interfaces import IMailService
[7470]35from waeup.sirp.smtp import (
36    encode_header_item, encode_address, encode_body, FakeSMTPDelivery,
[7473]37    send_mail)
[7470]38from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
39
40#
41# SMTP test config
42#
43
44# Also run tests that send mail to external servers?
45#   If you enable this, please make sure the external smtp hosts and receivers
46#   do exist really and are not bothered by being spammed by a test programme.
47EXTERNAL_MAIL_TESTS = False
48
49# Maybe existing receiver of externally sent mail. If this mail account
50# exists really, it might receive mail from the tests!
51EXTERNAL_MAIL_RECEIVER = 'no-user@waeup.org'
52
53# Names of mail deliveries to use when external mail tests are enabled.
54#   See local mail.zcml for names of available deliveries.
55EXTERNAL_DIRECT_DELIVERY = 'Direct SMTP on localhost'
56EXTERNAL_QUEUED_DELIVERY = 'Queued SMTP on localhost'
57
58#
59# end of SMTP test config
60#
61
62def external_mail_test(func):
63    if not EXTERNAL_MAIL_TESTS:
64        myself = __file__
65        if myself.endswith('.pyc'):
66            myself = myself[:-2]
67        print "WARNING: external mail tests are skipped!"
68        print "WARNING: edit %s to enable them." % myself
69        return
70    return func
71
72class HelperTests(unittest.TestCase):
73
74    def test_encode_header_item(self):
75        # encoding header items works with strings and unicodes, as
76        # long as we pass in utf-8 encoded stuff.
77        result1 = encode_header_item(u'Plain Name'.encode('utf-8'))
78        result2 = encode_header_item(u'Name with umläut'.encode('utf-8'))
79        result3 = encode_header_item(u'Plain Name')
80        result4 = encode_header_item(u'Name with umläut')
81        self.assertEqual(result1, u'Plain Name')
[7472]82        self.assertEqual(result2, u'=?iso-8859-1?q?Name_with_uml=E4ut?=')
[7470]83        self.assertEqual(result3, u'Plain Name')
[7472]84        self.assertEqual(result4, u'=?iso-8859-1?q?Name_with_uml=E4ut?=')
[7470]85        return
86
87    def test_encode_address(self):
88        # we can correctly encode address parts
89        result1 = encode_address('foo@bar.baz')
90        result2 = encode_address(u'foo@bar.baz', 'The Foo' )
91        result3 = encode_address('foo@bar.baz', u'The Foo')
92        result4 = encode_address('foo@bar.baz', u'With Umläut')
93        self.assertEqual(result1, 'foo@bar.baz')
94        self.assertEqual(result2, 'The Foo <foo@bar.baz>')
95        self.assertEqual(result3, 'The Foo <foo@bar.baz>')
[7472]96        self.assertEqual(result4,
97                         '=?iso-8859-1?q?With_Uml=E4ut?= <foo@bar.baz>')
[7470]98        return
99
100    def test_encode_body(self):
101        result1 = encode_body(u'Simple Text')
102        self.assertEqual(
103            str(result1).split('\n')[1:],
104            ['MIME-Version: 1.0',
105             'Content-Type: text/plain; charset="us-ascii"',
106             'Content-Transfer-Encoding: 7bit',
107             '',
108             'Simple Text'])
109        return
110
111    def test_encode_body_latin1_string(self):
112        # utf-8 encoded byte streams are transferred correctly when
113        # they contain chars unrepresentable in ascii but available in latin1
114        text = u'Simple text with Ümläut'.encode('utf-8')
115        result1 = encode_body(text)
116        result1 = str(result1).split('\n')[1:]
117        self.assertEqual(
118            result1,
119            ['MIME-Version: 1.0',
120             'Content-Type: text/plain; charset="iso-8859-1"',
121             'Content-Transfer-Encoding: quoted-printable',
122             '',
123             'Simple text with =DCml=E4ut'])
124        return
125
126    def test_encode_body_latin1_unicode(self):
127        # unicode strings are transferred correctly when they contain
128        # chars unrepresentable in ascii but available in latin1
129        text = u'Simple text with Ümläut'
130        result1 = encode_body(text)
131        result1 = str(result1).split('\n')[1:]
132        self.assertEqual(
133            result1,
134            ['MIME-Version: 1.0',
135             'Content-Type: text/plain; charset="iso-8859-1"',
136             'Content-Transfer-Encoding: quoted-printable',
137             '',
138             'Simple text with =DCml=E4ut'])
139        return
140
141    def test_encode_body_utf8_string(self):
142        # utf-8 encoded byte streams are transferred correctly when
143        # they contain chars unrepresentable in ascii but available in latin1
144        text = u"Simple text with ü and capital pi: " + unichr(0x3a0)
145        text = text.encode('utf-8') # turn unicode into byte stream
146        result1 = encode_body(text)
147        result1 = str(result1).split('\n')[1:]
148        self.assertEqual(
149            result1,
150            ['MIME-Version: 1.0',
151             'Content-Type: text/plain; charset="utf-8"',
152             'Content-Transfer-Encoding: base64',
153             '',
154             'U2ltcGxlIHRleHQgd2l0aCDDvCBhbmQgY2FwaXRhbCBwaTogzqA=', ''])
155        self.assertEqual(
156            base64.b64decode(result1[-2]).decode('utf-8'),
157            u"Simple text with ü and capital pi: " + unichr(0x3a0))
158        return
159
160    def test_encode_body_utf8_unicode(self):
161        # utf-8 encoded byte streams are transferred correctly when
162        # they contain chars unrepresentable in latin1
163        text = u"Simple text with ü and capital pi: " + unichr(0x3a0)
164        result1 = encode_body(text)
165        result1 = str(result1).split('\n')[1:]
166        self.assertEqual(
167            result1,
168            ['MIME-Version: 1.0',
169             'Content-Type: text/plain; charset="utf-8"',
170             'Content-Transfer-Encoding: base64',
171             '',
172             'U2ltcGxlIHRleHQgd2l0aCDDvCBhbmQgY2FwaXRhbCBwaTogzqA=', ''])
173        self.assertEqual(
174            base64.b64decode(result1[-2]).decode('utf-8'),
175            u"Simple text with ü and capital pi: " + unichr(0x3a0))
176        return
177
178class FunctionalMailerTests(FunctionalTestCase):
179
180    layer = FunctionalLayer
181
182    def setUp(self):
183        super(FunctionalMailerTests, self).setUp()
184        self.setup_logging()
185        return
186
187    def tearDown(self):
188        super(FunctionalMailerTests, self).tearDown()
189        self.teardown_logging()
190        return
191
192    def setup_logging(self):
193        # setup a log-handler that catches all fake mailer output
194        self.stream = StringIO()
195        handler = logging.StreamHandler(self.stream)
196        logger = logging.getLogger('test.smtp')
197        logger.addHandler(handler)
198        logger.setLevel(logging.INFO)
199        return
200
201    def get_fake_smtp_output(self):
202        # get output generated by fake mailer
203        self.stream.flush()
204        self.stream.seek(0)
205        return self.stream.read()
206
207    def teardown_logging(self):
208        # remove the log handler for fake mailer output
209        logger = logging.getLogger('test.smtp')
210        handlers = [x for x in logger.handlers]
211        for handler in handlers:
212            logger.removeHandler(handler)
213        return
214
215    def test_get_fake_mailer(self):
216        # we can get the fake mailer if we want
217        mailer = getUtility(IMailDelivery, name='No email service')
218        self.assertTrue(isinstance(mailer, FakeSMTPDelivery))
219        return
220
221    def test_get_default_mailer(self):
222        # we can get a default mailer if we want
223        mailer = getUtility(IMailService)
224        self.assertTrue(isinstance(mailer(), FakeSMTPDelivery))
225        return
226
227    def test_send_mail(self):
228        # we can really send mail.
229        mail_id = send_mail(
230            u'A sender', u'sender@example.com',
231            u'A recipient', u'recpt@example.com',
232            u'A subject',
233            u'This is a test mail.')
234        self.assertEqual(mail_id, 'fake-message-id@example.com')
235        self.assertEqual(
236            self.get_fake_smtp_output().split('\n'),
237            [u'Sending email from sender@example.com to recpt@example.com:',
238             u'Message:',
239             u'msg: MIME-Version: 1.0',
240             u'msg: Content-Type: text/plain; charset="us-ascii"',
241             u'msg: Content-Transfer-Encoding: 7bit',
242             u'msg: From: A sender <sender@example.com>',
243             u'msg: To: A recipient <recpt@example.com>',
244             u'msg: Subject: A subject',
245             u'msg: ',
246             u'msg: This is a test mail.',
247             u'']
248            )
249        return
250
251    def test_send_mail_utf8_strings(self):
252        # we can send mail with utf-8 encoded strings as input
253        mail_id = send_mail(
254            u'A sender', u'sender@example.com',
255            u'A recipient', u'recpt@example.com',
256            u'A subject',
257            u'This is a test mail with ümläut.'.encode('utf-8'))
258        self.assertEqual(mail_id, 'fake-message-id@example.com')
259        self.assertEqual(
260            self.get_fake_smtp_output().split('\n'),
261            [u'Sending email from sender@example.com to recpt@example.com:',
262             u'Message:', u'msg: MIME-Version: 1.0',
263             u'msg: Content-Type: text/plain; charset="iso-8859-1"',
264             u'msg: Content-Transfer-Encoding: quoted-printable',
265             u'msg: From: A sender <sender@example.com>',
266             u'msg: To: A recipient <recpt@example.com>',
267             u'msg: Subject: A subject',
268             u'msg: ',
269             u'msg: This is a test mail with =FCml=E4ut.',
270             u'']
271            )
272        return
273
274    def test_send_mail_utf8_unicode(self):
275        # we can send mail with utf-8 encoded unicode as input
276        mail_id = send_mail(
277            u'A sender', u'sender@example.com',
278            u'A recipient', u'recpt@example.com',
279            u'A subject',
280            u'This is a test mail with ümläut.')
281        self.assertEqual(mail_id, 'fake-message-id@example.com')
282        self.assertEqual(
283            self.get_fake_smtp_output().split('\n'),
284            [u'Sending email from sender@example.com to recpt@example.com:',
285             u'Message:', u'msg: MIME-Version: 1.0',
286             u'msg: Content-Type: text/plain; charset="iso-8859-1"',
287             u'msg: Content-Transfer-Encoding: quoted-printable',
288             u'msg: From: A sender <sender@example.com>',
289             u'msg: To: A recipient <recpt@example.com>',
290             u'msg: Subject: A subject',
291             u'msg: ',
292             u'msg: This is a test mail with =FCml=E4ut.',
293             u'']
294            )
295        return
296
297
298class ExternalMailerTests(FunctionalTestCase):
299
300    layer = FunctionalLayer
301
302    def setUp(self):
303        super(ExternalMailerTests, self).setUp()
304        # Setup a sample site for each test
305        app = University()
306        self.dc_root = tempfile.mkdtemp()
307        app['datacenter'].setStoragePath(self.dc_root)
308
309        # Prepopulate the ZODB...
310        self.getRootFolder()['app'] = app
311        self.app = self.getRootFolder()['app']
312        return
313
314    def tearDown(self):
315        super(ExternalMailerTests, self).tearDown()
316        shutil.rmtree(self.dc_root)
317        return
318
319    def test_config_default_mailer(self):
320        # The default mailer set in config is 'no mailer'.
321        self.assertEqual(
322            getattr(self.app.get('configuration', None), 'smtp_mailer'),
323            u'No email service')
324        return
325
326    @external_mail_test
327    def test_send_direct_mail(self):
328        # send mail using direct mail delivery
329        self.app['configuration'].smtp_mailer = EXTERNAL_DIRECT_DELIVERY
330        setSite(self.app)
331        result = send_mail(
332            'test program', 'no-reply@waeup.org',
333            'test mail receiver', EXTERNAL_MAIL_RECEIVER,
334            'Test Mail from WAeUP SIRP',
335            'Hi from test mailer!\n\nRegards,\nTest Programme\n'
336            )
337        import transaction
338        transaction.commit() # The mail is really sent when transactions is
339                             # committed
340        self.assertEqual(result, 'asd')
341        return
342
343    @external_mail_test
344    def test_send_queued_mail(self):
345        # send mail using queued mail delivery
346        self.app['configuration'].smtp_mailer = EXTERNAL_QUEUED_DELIVERY
347        setSite(self.app)
348        result = send_mail(
349            'test program', 'no-reply@waeup.org',
350            'test mail receiver', EXTERNAL_MAIL_RECEIVER,
351            'Test Mail from WAeUP SIRP',
352            'Hi from test mailer!\n\nRegards,\nTest Programme\n'
353            )
354        import transaction
355        transaction.commit() # The mail is really sent when transactions is
356                             # committed
357        self.assertEqual(result, 'asd')
358        return
Note: See TracBrowser for help on using the repository browser.