blob: b670afcf4e62eeb626164ef45925cb6d14d268e2 [file] [log] [blame]
Christian Heimesd3956292008-11-05 19:48:27 +00001"""Test script for poplib module."""
2
3# Modified by Giampaolo Rodola' to give poplib.POP3 and poplib.POP3_SSL
4# a real test suite
5
Guido van Rossumd8faa362007-04-27 19:54:29 +00006import poplib
Christian Heimesd3956292008-11-05 19:48:27 +00007import asyncore
8import asynchat
9import socket
10import os
Antoine Pitroud3f8ab82010-04-24 21:26:44 +000011import errno
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020012import threading
Guido van Rossumd8faa362007-04-27 19:54:29 +000013
Serhiy Storchaka43767632013-11-03 21:31:38 +020014from unittest import TestCase, skipUnless
Christian Heimesd3956292008-11-05 19:48:27 +000015from test import support as test_support
Hai Shi66abe982020-04-29 09:11:29 +080016from test.support import hashlib_helper
Serhiy Storchaka16994912020-04-25 10:06:29 +030017from test.support import socket_helper
Guido van Rossumd8faa362007-04-27 19:54:29 +000018
Serhiy Storchaka16994912020-04-25 10:06:29 +030019HOST = socket_helper.HOST
Christian Heimesd3956292008-11-05 19:48:27 +000020PORT = 0
Guido van Rossumd8faa362007-04-27 19:54:29 +000021
Antoine Pitrou8618d742012-11-23 20:13:48 +010022SUPPORTS_SSL = False
23if hasattr(poplib, 'POP3_SSL'):
24 import ssl
25
26 SUPPORTS_SSL = True
Christian Heimes1bc70682013-12-02 20:10:50 +010027 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem")
28 CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem")
Christian Heimese8a257c2013-12-15 21:44:43 +010029
Serhiy Storchaka43767632013-11-03 21:31:38 +020030requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported')
Antoine Pitrou8618d742012-11-23 20:13:48 +010031
Christian Heimesd3956292008-11-05 19:48:27 +000032# the dummy data returned by server when LIST and RETR commands are issued
33LIST_RESP = b'1 1\r\n2 2\r\n3 3\r\n4 4\r\n5 5\r\n.\r\n'
34RETR_RESP = b"""From: postmaster@python.org\
35\r\nContent-Type: text/plain\r\n\
36MIME-Version: 1.0\r\n\
37Subject: Dummy\r\n\
38\r\n\
39line1\r\n\
40line2\r\n\
41line3\r\n\
42.\r\n"""
Guido van Rossumd8faa362007-04-27 19:54:29 +000043
Christian Heimesd3956292008-11-05 19:48:27 +000044
45class DummyPOP3Handler(asynchat.async_chat):
46
Antoine Pitrou25cee192012-11-23 20:07:39 +010047 CAPAS = {'UIDL': [], 'IMPLEMENTATION': ['python-testlib-pop-server']}
R David Murrayb8cd3e42015-05-16 15:05:53 -040048 enable_UTF8 = False
Antoine Pitrou25cee192012-11-23 20:07:39 +010049
Christian Heimesd3956292008-11-05 19:48:27 +000050 def __init__(self, conn):
51 asynchat.async_chat.__init__(self, conn)
52 self.set_terminator(b"\r\n")
53 self.in_buffer = []
Mark Dickinsonea1158f2009-08-06 16:06:25 +000054 self.push('+OK dummy pop3 server ready. <timestamp>')
Antoine Pitrou8618d742012-11-23 20:13:48 +010055 self.tls_active = False
56 self.tls_starting = False
Christian Heimesd3956292008-11-05 19:48:27 +000057
58 def collect_incoming_data(self, data):
59 self.in_buffer.append(data)
60
61 def found_terminator(self):
62 line = b''.join(self.in_buffer)
63 line = str(line, 'ISO-8859-1')
64 self.in_buffer = []
65 cmd = line.split(' ')[0].lower()
66 space = line.find(' ')
67 if space != -1:
68 arg = line[space + 1:]
69 else:
70 arg = ""
71 if hasattr(self, 'cmd_' + cmd):
72 method = getattr(self, 'cmd_' + cmd)
73 method(arg)
74 else:
75 self.push('-ERR unrecognized POP3 command "%s".' %cmd)
76
77 def handle_error(self):
78 raise
79
80 def push(self, data):
81 asynchat.async_chat.push(self, data.encode("ISO-8859-1") + b'\r\n')
82
83 def cmd_echo(self, arg):
84 # sends back the received string (used by the test suite)
85 self.push(arg)
86
87 def cmd_user(self, arg):
88 if arg != "guido":
89 self.push("-ERR no such user")
90 self.push('+OK password required')
91
92 def cmd_pass(self, arg):
93 if arg != "python":
94 self.push("-ERR wrong password")
95 self.push('+OK 10 messages')
96
97 def cmd_stat(self, arg):
98 self.push('+OK 10 100')
99
100 def cmd_list(self, arg):
101 if arg:
Georg Brandl7e27abb2013-10-27 07:23:53 +0100102 self.push('+OK %s %s' % (arg, arg))
Christian Heimesd3956292008-11-05 19:48:27 +0000103 else:
104 self.push('+OK')
105 asynchat.async_chat.push(self, LIST_RESP)
106
107 cmd_uidl = cmd_list
108
109 def cmd_retr(self, arg):
110 self.push('+OK %s bytes' %len(RETR_RESP))
111 asynchat.async_chat.push(self, RETR_RESP)
112
113 cmd_top = cmd_retr
114
115 def cmd_dele(self, arg):
116 self.push('+OK message marked for deletion.')
117
118 def cmd_noop(self, arg):
119 self.push('+OK done nothing.')
120
121 def cmd_rpop(self, arg):
122 self.push('+OK done nothing.')
123
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000124 def cmd_apop(self, arg):
125 self.push('+OK done nothing.')
126
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000127 def cmd_quit(self, arg):
128 self.push('+OK closing.')
129 self.close_when_done()
130
Antoine Pitrou8618d742012-11-23 20:13:48 +0100131 def _get_capas(self):
132 _capas = dict(self.CAPAS)
133 if not self.tls_active and SUPPORTS_SSL:
134 _capas['STLS'] = []
135 return _capas
136
Antoine Pitrou25cee192012-11-23 20:07:39 +0100137 def cmd_capa(self, arg):
138 self.push('+OK Capability list follows')
Antoine Pitrou8618d742012-11-23 20:13:48 +0100139 if self._get_capas():
140 for cap, params in self._get_capas().items():
Antoine Pitrou25cee192012-11-23 20:07:39 +0100141 _ln = [cap]
142 if params:
143 _ln.extend(params)
144 self.push(' '.join(_ln))
145 self.push('.')
146
R David Murrayb8cd3e42015-05-16 15:05:53 -0400147 def cmd_utf8(self, arg):
148 self.push('+OK I know RFC6856'
149 if self.enable_UTF8
150 else '-ERR What is UTF8?!')
151
Antoine Pitrou8618d742012-11-23 20:13:48 +0100152 if SUPPORTS_SSL:
153
154 def cmd_stls(self, arg):
155 if self.tls_active is False:
156 self.push('+OK Begin TLS negotiation')
Christian Heimesd0486372016-09-10 23:23:33 +0200157 context = ssl.SSLContext()
158 context.load_cert_chain(CERTFILE)
159 tls_sock = context.wrap_socket(self.socket,
160 server_side=True,
161 do_handshake_on_connect=False,
162 suppress_ragged_eofs=False)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100163 self.del_channel()
164 self.set_socket(tls_sock)
165 self.tls_active = True
166 self.tls_starting = True
167 self.in_buffer = []
168 self._do_tls_handshake()
169 else:
170 self.push('-ERR Command not permitted when TLS active')
171
172 def _do_tls_handshake(self):
173 try:
174 self.socket.do_handshake()
175 except ssl.SSLError as err:
176 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
177 ssl.SSL_ERROR_WANT_WRITE):
178 return
179 elif err.args[0] == ssl.SSL_ERROR_EOF:
180 return self.handle_close()
Christian Heimes61d478c2018-01-27 15:51:38 +0100181 # TODO: SSLError does not expose alert information
Steve Dowere5f41d22018-05-16 17:50:29 -0400182 elif ("SSLV3_ALERT_BAD_CERTIFICATE" in err.args[1] or
183 "SSLV3_ALERT_CERTIFICATE_UNKNOWN" in err.args[1]):
Christian Heimes61d478c2018-01-27 15:51:38 +0100184 return self.handle_close()
Antoine Pitrou8618d742012-11-23 20:13:48 +0100185 raise
Andrew Svetlov0832af62012-12-18 23:10:48 +0200186 except OSError as err:
Antoine Pitrou8618d742012-11-23 20:13:48 +0100187 if err.args[0] == errno.ECONNABORTED:
188 return self.handle_close()
189 else:
190 self.tls_active = True
191 self.tls_starting = False
192
193 def handle_read(self):
194 if self.tls_starting:
195 self._do_tls_handshake()
196 else:
197 try:
198 asynchat.async_chat.handle_read(self)
199 except ssl.SSLEOFError:
200 self.handle_close()
Christian Heimesd3956292008-11-05 19:48:27 +0000201
202class DummyPOP3Server(asyncore.dispatcher, threading.Thread):
203
204 handler = DummyPOP3Handler
205
206 def __init__(self, address, af=socket.AF_INET):
207 threading.Thread.__init__(self)
208 asyncore.dispatcher.__init__(self)
Christian Heimes529525f2018-05-23 22:24:45 +0200209 self.daemon = True
Christian Heimesd3956292008-11-05 19:48:27 +0000210 self.create_socket(af, socket.SOCK_STREAM)
211 self.bind(address)
212 self.listen(5)
213 self.active = False
214 self.active_lock = threading.Lock()
215 self.host, self.port = self.socket.getsockname()[:2]
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000216 self.handler_instance = None
Christian Heimesd3956292008-11-05 19:48:27 +0000217
218 def start(self):
219 assert not self.active
220 self.__flag = threading.Event()
221 threading.Thread.start(self)
222 self.__flag.wait()
223
224 def run(self):
225 self.active = True
226 self.__flag.set()
Steve Dowere5f41d22018-05-16 17:50:29 -0400227 try:
228 while self.active and asyncore.socket_map:
229 with self.active_lock:
230 asyncore.loop(timeout=0.1, count=1)
231 finally:
232 asyncore.close_all(ignore_all=True)
Christian Heimesd3956292008-11-05 19:48:27 +0000233
234 def stop(self):
235 assert self.active
236 self.active = False
237 self.join()
238
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000239 def handle_accepted(self, conn, addr):
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000240 self.handler_instance = self.handler(conn)
Christian Heimesd3956292008-11-05 19:48:27 +0000241
242 def handle_connect(self):
243 self.close()
244 handle_read = handle_connect
245
246 def writable(self):
247 return 0
248
249 def handle_error(self):
250 raise
251
252
253class TestPOP3Class(TestCase):
254 def assertOK(self, resp):
255 self.assertTrue(resp.startswith(b"+OK"))
256
257 def setUp(self):
258 self.server = DummyPOP3Server((HOST, PORT))
259 self.server.start()
Victor Stinner7772b1a2019-12-11 22:17:04 +0100260 self.client = poplib.POP3(self.server.host, self.server.port,
261 timeout=test_support.LOOPBACK_TIMEOUT)
Christian Heimesd3956292008-11-05 19:48:27 +0000262
263 def tearDown(self):
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000264 self.client.close()
Christian Heimesd3956292008-11-05 19:48:27 +0000265 self.server.stop()
Victor Stinnerd403a292017-09-13 03:58:25 -0700266 # Explicitly clear the attribute to prevent dangling thread
267 self.server = None
Christian Heimesd3956292008-11-05 19:48:27 +0000268
269 def test_getwelcome(self):
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000270 self.assertEqual(self.client.getwelcome(),
271 b'+OK dummy pop3 server ready. <timestamp>')
Christian Heimesd3956292008-11-05 19:48:27 +0000272
273 def test_exceptions(self):
274 self.assertRaises(poplib.error_proto, self.client._shortcmd, 'echo -err')
275
276 def test_user(self):
277 self.assertOK(self.client.user('guido'))
278 self.assertRaises(poplib.error_proto, self.client.user, 'invalid')
279
280 def test_pass_(self):
281 self.assertOK(self.client.pass_('python'))
282 self.assertRaises(poplib.error_proto, self.client.user, 'invalid')
283
284 def test_stat(self):
285 self.assertEqual(self.client.stat(), (10, 100))
286
287 def test_list(self):
288 self.assertEqual(self.client.list()[1:],
289 ([b'1 1', b'2 2', b'3 3', b'4 4', b'5 5'],
290 25))
291 self.assertTrue(self.client.list('1').endswith(b"OK 1 1"))
292
293 def test_retr(self):
294 expected = (b'+OK 116 bytes',
295 [b'From: postmaster@python.org', b'Content-Type: text/plain',
296 b'MIME-Version: 1.0', b'Subject: Dummy',
297 b'', b'line1', b'line2', b'line3'],
298 113)
299 foo = self.client.retr('foo')
300 self.assertEqual(foo, expected)
301
Georg Brandl7e27abb2013-10-27 07:23:53 +0100302 def test_too_long_lines(self):
303 self.assertRaises(poplib.error_proto, self.client._shortcmd,
304 'echo +%s' % ((poplib._MAXLINE + 10) * 'a'))
305
Christian Heimesd3956292008-11-05 19:48:27 +0000306 def test_dele(self):
307 self.assertOK(self.client.dele('foo'))
308
309 def test_noop(self):
310 self.assertOK(self.client.noop())
311
312 def test_rpop(self):
313 self.assertOK(self.client.rpop('foo'))
314
Hai Shi66abe982020-04-29 09:11:29 +0800315 @hashlib_helper.requires_hashdigest('md5')
Jamie Davis0e6c8ee2018-03-04 00:33:32 -0500316 def test_apop_normal(self):
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000317 self.assertOK(self.client.apop('foo', 'dummypassword'))
318
Hai Shi66abe982020-04-29 09:11:29 +0800319 @hashlib_helper.requires_hashdigest('md5')
Jamie Davis0e6c8ee2018-03-04 00:33:32 -0500320 def test_apop_REDOS(self):
321 # Replace welcome with very long evil welcome.
322 # NB The upper bound on welcome length is currently 2048.
323 # At this length, evil input makes each apop call take
324 # on the order of milliseconds instead of microseconds.
325 evil_welcome = b'+OK' + (b'<' * 1000000)
326 with test_support.swap_attr(self.client, 'welcome', evil_welcome):
327 # The evil welcome is invalid, so apop should throw.
328 self.assertRaises(poplib.error_proto, self.client.apop, 'a', 'kb')
329
Christian Heimesd3956292008-11-05 19:48:27 +0000330 def test_top(self):
331 expected = (b'+OK 116 bytes',
332 [b'From: postmaster@python.org', b'Content-Type: text/plain',
333 b'MIME-Version: 1.0', b'Subject: Dummy', b'',
334 b'line1', b'line2', b'line3'],
335 113)
336 self.assertEqual(self.client.top(1, 1), expected)
337
338 def test_uidl(self):
339 self.client.uidl()
340 self.client.uidl('foo')
341
R David Murrayb8cd3e42015-05-16 15:05:53 -0400342 def test_utf8_raises_if_unsupported(self):
343 self.server.handler.enable_UTF8 = False
344 self.assertRaises(poplib.error_proto, self.client.utf8)
345
346 def test_utf8(self):
347 self.server.handler.enable_UTF8 = True
348 expected = b'+OK I know RFC6856'
349 result = self.client.utf8()
350 self.assertEqual(result, expected)
351
Antoine Pitrou25cee192012-11-23 20:07:39 +0100352 def test_capa(self):
353 capa = self.client.capa()
354 self.assertTrue('IMPLEMENTATION' in capa.keys())
355
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000356 def test_quit(self):
357 resp = self.client.quit()
358 self.assertTrue(resp)
359 self.assertIsNone(self.client.sock)
360 self.assertIsNone(self.client.file)
361
Serhiy Storchaka43767632013-11-03 21:31:38 +0200362 @requires_ssl
363 def test_stls_capa(self):
364 capa = self.client.capa()
365 self.assertTrue('STLS' in capa.keys())
Christian Heimesd3956292008-11-05 19:48:27 +0000366
Serhiy Storchaka43767632013-11-03 21:31:38 +0200367 @requires_ssl
368 def test_stls(self):
369 expected = b'+OK Begin TLS negotiation'
370 resp = self.client.stls()
371 self.assertEqual(resp, expected)
Christian Heimesd3956292008-11-05 19:48:27 +0000372
Serhiy Storchaka43767632013-11-03 21:31:38 +0200373 @requires_ssl
374 def test_stls_context(self):
375 expected = b'+OK Begin TLS negotiation'
Christian Heimesa170fa12017-09-15 20:27:30 +0200376 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes1bc70682013-12-02 20:10:50 +0100377 ctx.load_verify_locations(CAFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +0200378 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
379 self.assertEqual(ctx.check_hostname, True)
Christian Heimes1bc70682013-12-02 20:10:50 +0100380 with self.assertRaises(ssl.CertificateError):
381 resp = self.client.stls(context=ctx)
Victor Stinner7772b1a2019-12-11 22:17:04 +0100382 self.client = poplib.POP3("localhost", self.server.port,
383 timeout=test_support.LOOPBACK_TIMEOUT)
Serhiy Storchaka43767632013-11-03 21:31:38 +0200384 resp = self.client.stls(context=ctx)
385 self.assertEqual(resp, expected)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100386
387
388if SUPPORTS_SSL:
Antoine Pitrou3f73e4c2014-04-29 10:27:09 +0200389 from test.test_ftplib import SSLConnection
Christian Heimesd3956292008-11-05 19:48:27 +0000390
Antoine Pitrou3f73e4c2014-04-29 10:27:09 +0200391 class DummyPOP3_SSLHandler(SSLConnection, DummyPOP3Handler):
Christian Heimesd3956292008-11-05 19:48:27 +0000392
393 def __init__(self, conn):
394 asynchat.async_chat.__init__(self, conn)
Antoine Pitrou3f73e4c2014-04-29 10:27:09 +0200395 self.secure_connection()
Christian Heimesd3956292008-11-05 19:48:27 +0000396 self.set_terminator(b"\r\n")
397 self.in_buffer = []
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000398 self.push('+OK dummy pop3 server ready. <timestamp>')
Antoine Pitrou3f73e4c2014-04-29 10:27:09 +0200399 self.tls_active = True
400 self.tls_starting = False
Christian Heimesd3956292008-11-05 19:48:27 +0000401
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000402
Serhiy Storchaka43767632013-11-03 21:31:38 +0200403@requires_ssl
404class TestPOP3_SSLClass(TestPOP3Class):
405 # repeat previous tests by using poplib.POP3_SSL
Christian Heimesd3956292008-11-05 19:48:27 +0000406
Serhiy Storchaka43767632013-11-03 21:31:38 +0200407 def setUp(self):
408 self.server = DummyPOP3Server((HOST, PORT))
409 self.server.handler = DummyPOP3_SSLHandler
410 self.server.start()
411 self.client = poplib.POP3_SSL(self.server.host, self.server.port)
Christian Heimesd3956292008-11-05 19:48:27 +0000412
Serhiy Storchaka43767632013-11-03 21:31:38 +0200413 def test__all__(self):
414 self.assertIn('POP3_SSL', poplib.__all__)
Christian Heimesd3956292008-11-05 19:48:27 +0000415
Serhiy Storchaka43767632013-11-03 21:31:38 +0200416 def test_context(self):
Christian Heimesa170fa12017-09-15 20:27:30 +0200417 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
418 ctx.check_hostname = False
419 ctx.verify_mode = ssl.CERT_NONE
Serhiy Storchaka43767632013-11-03 21:31:38 +0200420 self.assertRaises(ValueError, poplib.POP3_SSL, self.server.host,
421 self.server.port, keyfile=CERTFILE, context=ctx)
422 self.assertRaises(ValueError, poplib.POP3_SSL, self.server.host,
423 self.server.port, certfile=CERTFILE, context=ctx)
424 self.assertRaises(ValueError, poplib.POP3_SSL, self.server.host,
425 self.server.port, keyfile=CERTFILE,
426 certfile=CERTFILE, context=ctx)
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000427
Serhiy Storchaka43767632013-11-03 21:31:38 +0200428 self.client.quit()
429 self.client = poplib.POP3_SSL(self.server.host, self.server.port,
430 context=ctx)
431 self.assertIsInstance(self.client.sock, ssl.SSLSocket)
432 self.assertIs(self.client.sock.context, ctx)
433 self.assertTrue(self.client.noop().startswith(b'+OK'))
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000434
Serhiy Storchaka43767632013-11-03 21:31:38 +0200435 def test_stls(self):
436 self.assertRaises(poplib.error_proto, self.client.stls)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100437
Serhiy Storchaka43767632013-11-03 21:31:38 +0200438 test_stls_context = test_stls
Antoine Pitrou8618d742012-11-23 20:13:48 +0100439
Serhiy Storchaka43767632013-11-03 21:31:38 +0200440 def test_stls_capa(self):
441 capa = self.client.capa()
442 self.assertFalse('STLS' in capa.keys())
Antoine Pitrou8618d742012-11-23 20:13:48 +0100443
444
Serhiy Storchaka43767632013-11-03 21:31:38 +0200445@requires_ssl
446class TestPOP3_TLSClass(TestPOP3Class):
447 # repeat previous tests by using poplib.POP3.stls()
Antoine Pitrou8618d742012-11-23 20:13:48 +0100448
Serhiy Storchaka43767632013-11-03 21:31:38 +0200449 def setUp(self):
450 self.server = DummyPOP3Server((HOST, PORT))
451 self.server.start()
Victor Stinner7772b1a2019-12-11 22:17:04 +0100452 self.client = poplib.POP3(self.server.host, self.server.port,
453 timeout=test_support.LOOPBACK_TIMEOUT)
Serhiy Storchaka43767632013-11-03 21:31:38 +0200454 self.client.stls()
Antoine Pitrou8618d742012-11-23 20:13:48 +0100455
Serhiy Storchaka43767632013-11-03 21:31:38 +0200456 def tearDown(self):
457 if self.client.file is not None and self.client.sock is not None:
458 try:
459 self.client.quit()
460 except poplib.error_proto:
461 # happens in the test_too_long_lines case; the overlong
462 # response will be treated as response to QUIT and raise
463 # this exception
Victor Stinner28dd6de2013-12-09 01:15:10 +0100464 self.client.close()
Serhiy Storchaka43767632013-11-03 21:31:38 +0200465 self.server.stop()
Victor Stinnerd403a292017-09-13 03:58:25 -0700466 # Explicitly clear the attribute to prevent dangling thread
467 self.server = None
Antoine Pitrou8618d742012-11-23 20:13:48 +0100468
Serhiy Storchaka43767632013-11-03 21:31:38 +0200469 def test_stls(self):
470 self.assertRaises(poplib.error_proto, self.client.stls)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100471
Serhiy Storchaka43767632013-11-03 21:31:38 +0200472 test_stls_context = test_stls
Antoine Pitrou8618d742012-11-23 20:13:48 +0100473
Serhiy Storchaka43767632013-11-03 21:31:38 +0200474 def test_stls_capa(self):
475 capa = self.client.capa()
476 self.assertFalse(b'STLS' in capa.keys())
Antoine Pitrou8618d742012-11-23 20:13:48 +0100477
Christian Heimesd3956292008-11-05 19:48:27 +0000478
479class TestTimeouts(TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000480
481 def setUp(self):
482 self.evt = threading.Event()
Christian Heimes5e696852008-04-09 08:37:03 +0000483 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Charles-François Natali83ef2542011-12-14 19:28:56 +0100484 self.sock.settimeout(60) # Safety net. Look issue 11812
Serhiy Storchaka16994912020-04-25 10:06:29 +0300485 self.port = socket_helper.bind_port(self.sock)
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900486 self.thread = threading.Thread(target=self.server, args=(self.evt, self.sock))
Christian Heimes529525f2018-05-23 22:24:45 +0200487 self.thread.daemon = True
Charles-François Natali83ef2542011-12-14 19:28:56 +0100488 self.thread.start()
489 self.evt.wait()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000490
491 def tearDown(self):
Charles-François Natali83ef2542011-12-14 19:28:56 +0100492 self.thread.join()
Victor Stinnerd403a292017-09-13 03:58:25 -0700493 # Explicitly clear the attribute to prevent dangling thread
494 self.thread = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000495
Christian Heimesd3956292008-11-05 19:48:27 +0000496 def server(self, evt, serv):
Charles-François Natali6e204602014-07-23 19:28:13 +0100497 serv.listen()
Charles-François Natali83ef2542011-12-14 19:28:56 +0100498 evt.set()
Christian Heimesd3956292008-11-05 19:48:27 +0000499 try:
500 conn, addr = serv.accept()
Christian Heimesd3956292008-11-05 19:48:27 +0000501 conn.send(b"+ Hola mundo\n")
502 conn.close()
Charles-François Natali83ef2542011-12-14 19:28:56 +0100503 except socket.timeout:
504 pass
Christian Heimesd3956292008-11-05 19:48:27 +0000505 finally:
506 serv.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000507
508 def testTimeoutDefault(self):
Serhiy Storchaka578c6772014-02-08 15:06:08 +0200509 self.assertIsNone(socket.getdefaulttimeout())
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900510 socket.setdefaulttimeout(test_support.LOOPBACK_TIMEOUT)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000511 try:
Charles-François Natali83ef2542011-12-14 19:28:56 +0100512 pop = poplib.POP3(HOST, self.port)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000513 finally:
514 socket.setdefaulttimeout(None)
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900515 self.assertEqual(pop.sock.gettimeout(), test_support.LOOPBACK_TIMEOUT)
Victor Stinnerd165e142017-09-13 05:53:10 -0700516 pop.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000517
518 def testTimeoutNone(self):
Serhiy Storchaka578c6772014-02-08 15:06:08 +0200519 self.assertIsNone(socket.getdefaulttimeout())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000520 socket.setdefaulttimeout(30)
521 try:
Christian Heimes5e696852008-04-09 08:37:03 +0000522 pop = poplib.POP3(HOST, self.port, timeout=None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000523 finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +0000524 socket.setdefaulttimeout(None)
Serhiy Storchaka578c6772014-02-08 15:06:08 +0200525 self.assertIsNone(pop.sock.gettimeout())
Victor Stinnerd165e142017-09-13 05:53:10 -0700526 pop.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000527
Georg Brandlf78e02b2008-06-10 17:40:04 +0000528 def testTimeoutValue(self):
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900529 pop = poplib.POP3(HOST, self.port, timeout=test_support.LOOPBACK_TIMEOUT)
530 self.assertEqual(pop.sock.gettimeout(), test_support.LOOPBACK_TIMEOUT)
Victor Stinnerd165e142017-09-13 05:53:10 -0700531 pop.close()
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900532 with self.assertRaises(ValueError):
533 poplib.POP3(HOST, self.port, timeout=0)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000534
535
Christian Heimesd3956292008-11-05 19:48:27 +0000536def test_main():
Serhiy Storchaka43767632013-11-03 21:31:38 +0200537 tests = [TestPOP3Class, TestTimeouts,
538 TestPOP3_SSLClass, TestPOP3_TLSClass]
Christian Heimesd3956292008-11-05 19:48:27 +0000539 thread_info = test_support.threading_setup()
540 try:
541 test_support.run_unittest(*tests)
542 finally:
543 test_support.threading_cleanup(*thread_info)
544
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545
546if __name__ == '__main__':
547 test_main()