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

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

Use iso-8859-1 instead of latin1 as mail part encoding name. Looks like Python 2.7 insists on the former as proper name.

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