/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2007, 2009, 2010, 2011 Canonical Ltd
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
16
6791.2.3 by Jelmer Vernooij
Fix more imports.
17
try:
18
    from email.message import Message
19
except ImportError:  # python < 3
20
    from email.Message import Message
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
21
import errno
22
import smtplib
23
import socket
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
24
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
25
from breezy import (
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
26
    config,
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
27
    email_message,
28
    smtp_connection,
29
    tests,
30
    ui,
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
31
    )
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
32
33
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
34
def connection_refuser():
35
    def connect(server):
36
        raise socket.error(errno.ECONNREFUSED, 'Connection Refused')
37
    smtp = smtplib.SMTP()
38
    smtp.connect = connect
39
    return smtp
40
41
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
42
class StubSMTPFactory(object):
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
43
    """A fake SMTP connection to test the connection setup."""
7143.15.2 by Jelmer Vernooij
Run autopep8.
44
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
45
    def __init__(self, fail_on=None, smtp_features=None):
46
        self._fail_on = fail_on or []
47
        self._calls = []
48
        self._smtp_features = smtp_features or []
49
        self._ehlo_called = False
50
51
    def __call__(self):
52
        # The factory pretends to be a connection
53
        return self
54
55
    def connect(self, server):
56
        self._calls.append(('connect', server))
57
58
    def helo(self):
59
        self._calls.append(('helo',))
60
        if 'helo' in self._fail_on:
61
            return 500, 'helo failure'
62
        else:
63
            return 200, 'helo success'
64
65
    def ehlo(self):
66
        self._calls.append(('ehlo',))
67
        if 'ehlo' in self._fail_on:
68
            return 500, 'ehlo failure'
69
        else:
70
            self._ehlo_called = True
71
            return 200, 'ehlo success'
72
73
    def has_extn(self, extension):
74
        self._calls.append(('has_extn', extension))
75
        return self._ehlo_called and extension in self._smtp_features
76
77
    def starttls(self):
78
        self._calls.append(('starttls',))
79
        if 'starttls' in self._fail_on:
80
            return 500, 'starttls failure'
81
        else:
82
            self._ehlo_called = True
83
            return 200, 'starttls success'
84
85
2900.2.17 by Vincent Ladeuil
merge bzr.dev
86
class WideOpenSMTPFactory(StubSMTPFactory):
87
    """A fake smtp server that implements login by accepting anybody."""
88
89
    def login(self, user, password):
4147.1.1 by James Henstridge
Ensure that byte strings are passed to SMTP.login(), as passing unicode
90
        self._calls.append(('login', user, password))
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
91
92
93
class TestSMTPConnection(tests.TestCaseInTempDir):
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
94
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
95
    def get_connection(self, text, smtp_factory=None):
6393.1.1 by Vincent Ladeuil
Provides MemoryStack to simplify configuration setup in tests
96
        my_config = config.MemoryStack(text)
6379.8.2 by Jelmer Vernooij
Update tests.
97
        return smtp_connection.SMTPConnection(
98
            my_config, _smtp_factory=smtp_factory)
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
99
100
    def test_defaults(self):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
101
        conn = self.get_connection(b'')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
102
        self.assertEqual('localhost', conn._smtp_server)
103
        self.assertEqual(None, conn._smtp_username)
104
        self.assertEqual(None, conn._smtp_password)
105
106
    def test_smtp_server(self):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
107
        conn = self.get_connection(b'smtp_server=host:10')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
108
        self.assertEqual('host:10', conn._smtp_server)
109
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
110
    def test_missing_server(self):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
111
        conn = self.get_connection(b'', smtp_factory=connection_refuser)
6734.1.1 by Jelmer Vernooij
Fix more imports.
112
        self.assertRaises(smtp_connection.DefaultSMTPConnectionRefused,
113
                          conn._connect)
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
114
        conn = self.get_connection(b'smtp_server=smtp.example.com',
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
115
                                   smtp_factory=connection_refuser)
6734.1.1 by Jelmer Vernooij
Fix more imports.
116
        self.assertRaises(smtp_connection.SMTPConnectionRefused, conn._connect)
2694.2.1 by Aaron Bentley
Make error handling nicer when SMTP server not working
117
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
118
    def test_smtp_username(self):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
119
        conn = self.get_connection(b'')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
120
        self.assertIs(None, conn._smtp_username)
121
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
122
        conn = self.get_connection(b'smtp_username=joebody')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
123
        self.assertEqual(u'joebody', conn._smtp_username)
124
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
125
    def test_smtp_password_from_config(self):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
126
        conn = self.get_connection(b'')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
127
        self.assertIs(None, conn._smtp_password)
128
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
129
        conn = self.get_connection(b'smtp_password=mypass')
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
130
        self.assertEqual(u'mypass', conn._smtp_password)
131
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
132
    def test_smtp_password_from_user(self):
133
        user = 'joe'
134
        password = 'hispass'
2900.2.17 by Vincent Ladeuil
merge bzr.dev
135
        factory = WideOpenSMTPFactory()
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
136
        conn = self.get_connection(
7143.15.2 by Jelmer Vernooij
Run autopep8.
137
            b'[DEFAULT]\nsmtp_username=%s\n' % user.encode('ascii'),
138
            smtp_factory=factory)
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
139
        self.assertIs(None, conn._smtp_password)
140
4449.3.40 by Martin Pool
Update SMTP tests to use CannedInputUIFactory
141
        ui.ui_factory = ui.CannedInputUIFactory([password])
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
142
        conn._connect()
143
        self.assertEqual(password, conn._smtp_password)
144
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
145
    def test_smtp_password_from_auth_config(self):
146
        user = 'joe'
147
        password = 'hispass'
2900.2.17 by Vincent Ladeuil
merge bzr.dev
148
        factory = WideOpenSMTPFactory()
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
149
        conn = self.get_connection(
150
            b'[DEFAULT]\nsmtp_username=%s\n' % user.encode('ascii'),
151
            smtp_factory=factory)
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
152
        self.assertEqual(user, conn._smtp_username)
153
        self.assertIs(None, conn._smtp_password)
154
        # Create a config file with the right password
155
        conf = config.AuthenticationConfig()
156
        conf._get_config().update({'smtptest':
7143.15.2 by Jelmer Vernooij
Run autopep8.
157
                                   {'scheme': 'smtp', 'user': user,
158
                                    'password': password}})
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
159
        conf._save()
160
161
        conn._connect()
162
        self.assertEqual(password, conn._smtp_password)
163
4147.1.1 by James Henstridge
Ensure that byte strings are passed to SMTP.login(), as passing unicode
164
    def test_authenticate_with_byte_strings(self):
7045.4.8 by Jelmer Vernooij
Fix another 128 tests on python 3.
165
        user = b'joe'
5345.2.4 by Vincent Ladeuil
Fix fallouts, including an unclear test.
166
        unicode_pass = u'h\xECspass'
167
        utf8_pass = unicode_pass.encode('utf-8')
4147.1.1 by James Henstridge
Ensure that byte strings are passed to SMTP.login(), as passing unicode
168
        factory = WideOpenSMTPFactory()
169
        conn = self.get_connection(
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
170
            b'[DEFAULT]\nsmtp_username=%s\nsmtp_password=%s\n'
6379.8.2 by Jelmer Vernooij
Update tests.
171
            % (user, utf8_pass), smtp_factory=factory)
5345.2.4 by Vincent Ladeuil
Fix fallouts, including an unclear test.
172
        self.assertEqual(unicode_pass, conn._smtp_password)
4147.1.1 by James Henstridge
Ensure that byte strings are passed to SMTP.login(), as passing unicode
173
        conn._connect()
174
        self.assertEqual([('connect', 'localhost'),
175
                          ('ehlo',),
176
                          ('has_extn', 'starttls'),
5345.2.4 by Vincent Ladeuil
Fix fallouts, including an unclear test.
177
                          ('login', user, utf8_pass)], factory._calls)
4147.1.2 by James Henstridge
Encode usernames and passwords as UTF-8 rather than ASCII. While
178
        smtp_username, smtp_password = factory._calls[-1][1:]
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
179
        self.assertIsInstance(smtp_username, bytes)
180
        self.assertIsInstance(smtp_password, bytes)
4147.1.1 by James Henstridge
Ensure that byte strings are passed to SMTP.login(), as passing unicode
181
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
182
    def test_create_connection(self):
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
183
        factory = StubSMTPFactory()
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
184
        conn = self.get_connection(b'', smtp_factory=factory)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
185
        conn._create_connection()
186
        self.assertEqual([('connect', 'localhost'),
187
                          ('ehlo',),
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
188
                          ('has_extn', 'starttls')], factory._calls)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
189
190
    def test_create_connection_ehlo_fails(self):
191
        # Check that we call HELO if EHLO failed.
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
192
        factory = StubSMTPFactory(fail_on=['ehlo'])
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
193
        conn = self.get_connection(b'', smtp_factory=factory)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
194
        conn._create_connection()
195
        self.assertEqual([('connect', 'localhost'),
196
                          ('ehlo',),
197
                          ('helo',),
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
198
                          ('has_extn', 'starttls')], factory._calls)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
199
200
    def test_create_connection_ehlo_helo_fails(self):
201
        # Check that we raise an exception if both EHLO and HELO fail.
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
202
        factory = StubSMTPFactory(fail_on=['ehlo', 'helo'])
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
203
        conn = self.get_connection(b'', smtp_factory=factory)
6734.1.1 by Jelmer Vernooij
Fix more imports.
204
        self.assertRaises(smtp_connection.SMTPError, conn._create_connection)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
205
        self.assertEqual([('connect', 'localhost'),
206
                          ('ehlo',),
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
207
                          ('helo',)], factory._calls)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
208
209
    def test_create_connection_starttls(self):
210
        # Check that STARTTLS plus a second EHLO are called if the
211
        # server says it supports the feature.
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
212
        factory = StubSMTPFactory(smtp_features=['starttls'])
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
213
        conn = self.get_connection(b'', smtp_factory=factory)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
214
        conn._create_connection()
215
        self.assertEqual([('connect', 'localhost'),
216
                          ('ehlo',),
217
                          ('has_extn', 'starttls'),
218
                          ('starttls',),
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
219
                          ('ehlo',)], factory._calls)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
220
221
    def test_create_connection_starttls_fails(self):
222
        # Check that we raise an exception if the server claims to
223
        # support STARTTLS, but then fails when we try to activate it.
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
224
        factory = StubSMTPFactory(fail_on=['starttls'],
225
                                  smtp_features=['starttls'])
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
226
        conn = self.get_connection(b'', smtp_factory=factory)
6734.1.1 by Jelmer Vernooij
Fix more imports.
227
        self.assertRaises(smtp_connection.SMTPError, conn._create_connection)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
228
        self.assertEqual([('connect', 'localhost'),
229
                          ('ehlo',),
230
                          ('has_extn', 'starttls'),
2898.2.2 by James Henstridge
Fix test helper class naming, per John's review comments.
231
                          ('starttls',)], factory._calls)
2898.2.1 by James Henstridge
Update SMTPConnection._create_connection to better follow the SMTP
232
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
233
    def test_get_message_addresses(self):
234
        msg = Message()
235
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
236
        from_, to = smtp_connection.SMTPConnection.get_message_addresses(msg)
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
237
        self.assertEqual('', from_)
238
        self.assertEqual([], to)
239
240
        msg['From'] = '"J. Random Developer" <jrandom@example.com>'
241
        msg['To'] = 'John Doe <john@doe.com>, Jane Doe <jane@doe.com>'
242
        msg['CC'] = u'Pepe P\xe9rez <pperez@ejemplo.com>'
243
        msg['Bcc'] = 'user@localhost'
244
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
245
        from_, to = smtp_connection.SMTPConnection.get_message_addresses(msg)
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
246
        self.assertEqual('jrandom@example.com', from_)
247
        self.assertEqual(sorted(['john@doe.com', 'jane@doe.com',
7143.15.2 by Jelmer Vernooij
Run autopep8.
248
                                 'pperez@ejemplo.com', 'user@localhost']), sorted(to))
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
249
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
250
        # now with breezy's EmailMessage
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
251
        msg = email_message.EmailMessage(
252
            '"J. Random Developer" <jrandom@example.com>',
253
            ['John Doe <john@doe.com>', 'Jane Doe <jane@doe.com>',
7143.15.2 by Jelmer Vernooij
Run autopep8.
254
             u'Pepe P\xe9rez <pperez@ejemplo.com>', 'user@localhost'],
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
255
            'subject')
256
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
257
        from_, to = smtp_connection.SMTPConnection.get_message_addresses(msg)
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
258
        self.assertEqual('jrandom@example.com', from_)
259
        self.assertEqual(sorted(['john@doe.com', 'jane@doe.com',
7143.15.2 by Jelmer Vernooij
Run autopep8.
260
                                 'pperez@ejemplo.com', 'user@localhost']), sorted(to))
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
261
2535.2.1 by Adeodato Simó
New SMTPConnection class, a reduced version of that in bzr-email.
262
    def test_destination_address_required(self):
263
        msg = Message()
264
        msg['From'] = '"J. Random Developer" <jrandom@example.com>'
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
265
        self.assertRaises(
6734.1.1 by Jelmer Vernooij
Fix more imports.
266
            smtp_connection.NoDestinationAddress,
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
267
            smtp_connection.SMTPConnection(config.MemoryStack(b"")
6393.1.1 by Vincent Ladeuil
Provides MemoryStack to simplify configuration setup in tests
268
                                           ).send_email, msg)
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
269
270
        msg = email_message.EmailMessage('from@from.com', '', 'subject')
271
        self.assertRaises(
6734.1.1 by Jelmer Vernooij
Fix more imports.
272
            smtp_connection.NoDestinationAddress,
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
273
            smtp_connection.SMTPConnection(config.MemoryStack(b"")
6393.1.1 by Vincent Ladeuil
Provides MemoryStack to simplify configuration setup in tests
274
                                           ).send_email, msg)
2900.2.11 by Vincent Ladeuil
Make smtp aware of authentication config.
275
276
        msg = email_message.EmailMessage('from@from.com', [], 'subject')
277
        self.assertRaises(
6734.1.1 by Jelmer Vernooij
Fix more imports.
278
            smtp_connection.NoDestinationAddress,
7045.4.12 by Jelmer Vernooij
Fix remaining smtp tests.
279
            smtp_connection.SMTPConnection(config.MemoryStack(b"")
6393.1.1 by Vincent Ladeuil
Provides MemoryStack to simplify configuration setup in tests
280
                                           ).send_email, msg)