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

Last change on this file since 8959 was 7506, checked in by Henrik Bettermann, 13 years ago

Let test pass if EXTERNAL_MAIL_TESTS == True.

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