blob: 708ac41922b0b0a61208afc2dd6970b8dce40b6f [file] [log] [blame]
Benjamin Petersonbe17a112008-09-27 21:49:47 +00001"""Test script for ftplib module."""
2
Antoine Pitrouf988cd02009-11-17 20:21:14 +00003# Modified by Giampaolo Rodola' to test FTP class, IPv6 and TLS
4# environment
Benjamin Petersonbe17a112008-09-27 21:49:47 +00005
Guido van Rossumd8faa362007-04-27 19:54:29 +00006import ftplib
Benjamin Petersonbe17a112008-09-27 21:49:47 +00007import threading
8import asyncore
9import asynchat
10import socket
11import io
Antoine Pitrouf988cd02009-11-17 20:21:14 +000012import errno
13import os
14try:
15 import ssl
16except ImportError:
17 ssl = None
Guido van Rossumd8faa362007-04-27 19:54:29 +000018
19from unittest import TestCase
Benjamin Petersonee8712c2008-05-20 21:35:26 +000020from test import support
Benjamin Petersonbe17a112008-09-27 21:49:47 +000021from test.support import HOST
Guido van Rossumd8faa362007-04-27 19:54:29 +000022
Benjamin Petersonbe17a112008-09-27 21:49:47 +000023# the dummy data returned by server over the data channel when
24# RETR, LIST and NLST commands are issued
25RETR_DATA = 'abcde12345\r\n' * 1000
26LIST_DATA = 'foo\r\nbar\r\n'
27NLST_DATA = 'foo\r\nbar\r\n'
Christian Heimes836baa52008-02-26 08:18:30 +000028
Christian Heimes836baa52008-02-26 08:18:30 +000029
Benjamin Petersonbe17a112008-09-27 21:49:47 +000030class DummyDTPHandler(asynchat.async_chat):
31
32 def __init__(self, conn, baseclass):
33 asynchat.async_chat.__init__(self, conn)
34 self.baseclass = baseclass
35 self.baseclass.last_received_data = ''
36
37 def handle_read(self):
38 self.baseclass.last_received_data += self.recv(1024).decode('ascii')
39
40 def handle_close(self):
41 self.baseclass.push('226 transfer complete')
42 self.close()
43
44 def push(self, what):
45 super(DummyDTPHandler, self).push(what.encode('ascii'))
46
47
48class DummyFTPHandler(asynchat.async_chat):
49
Antoine Pitrouf988cd02009-11-17 20:21:14 +000050 dtp_handler = DummyDTPHandler
51
Benjamin Petersonbe17a112008-09-27 21:49:47 +000052 def __init__(self, conn):
53 asynchat.async_chat.__init__(self, conn)
54 self.set_terminator(b"\r\n")
55 self.in_buffer = []
56 self.dtp = None
57 self.last_received_cmd = None
58 self.last_received_data = ''
59 self.next_response = ''
60 self.push('220 welcome')
61
62 def collect_incoming_data(self, data):
63 self.in_buffer.append(data)
64
65 def found_terminator(self):
66 line = b''.join(self.in_buffer).decode('ascii')
67 self.in_buffer = []
68 if self.next_response:
69 self.push(self.next_response)
70 self.next_response = ''
71 cmd = line.split(' ')[0].lower()
72 self.last_received_cmd = cmd
73 space = line.find(' ')
74 if space != -1:
75 arg = line[space + 1:]
76 else:
77 arg = ""
78 if hasattr(self, 'cmd_' + cmd):
79 method = getattr(self, 'cmd_' + cmd)
80 method(arg)
81 else:
82 self.push('550 command "%s" not understood.' %cmd)
83
84 def handle_error(self):
85 raise
86
87 def push(self, data):
88 asynchat.async_chat.push(self, data.encode('ascii') + b'\r\n')
89
90 def cmd_port(self, arg):
91 addr = list(map(int, arg.split(',')))
92 ip = '%d.%d.%d.%d' %tuple(addr[:4])
93 port = (addr[4] * 256) + addr[5]
94 s = socket.create_connection((ip, port), timeout=2)
Antoine Pitrouf988cd02009-11-17 20:21:14 +000095 self.dtp = self.dtp_handler(s, baseclass=self)
Benjamin Petersonbe17a112008-09-27 21:49:47 +000096 self.push('200 active data connection established')
97
98 def cmd_pasv(self, arg):
99 sock = socket.socket()
100 sock.bind((self.socket.getsockname()[0], 0))
101 sock.listen(5)
102 sock.settimeout(2)
103 ip, port = sock.getsockname()[:2]
104 ip = ip.replace('.', ','); p1 = port / 256; p2 = port % 256
105 self.push('227 entering passive mode (%s,%d,%d)' %(ip, p1, p2))
106 conn, addr = sock.accept()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000107 self.dtp = self.dtp_handler(conn, baseclass=self)
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000108
109 def cmd_eprt(self, arg):
110 af, ip, port = arg.split(arg[0])[1:-1]
111 port = int(port)
112 s = socket.create_connection((ip, port), timeout=2)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000113 self.dtp = self.dtp_handler(s, baseclass=self)
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000114 self.push('200 active data connection established')
115
116 def cmd_epsv(self, arg):
117 sock = socket.socket(socket.AF_INET6)
118 sock.bind((self.socket.getsockname()[0], 0))
119 sock.listen(5)
120 sock.settimeout(2)
121 port = sock.getsockname()[1]
122 self.push('229 entering extended passive mode (|||%d|)' %port)
123 conn, addr = sock.accept()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000124 self.dtp = self.dtp_handler(conn, baseclass=self)
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000125
126 def cmd_echo(self, arg):
127 # sends back the received string (used by the test suite)
128 self.push(arg)
129
130 def cmd_user(self, arg):
131 self.push('331 username ok')
132
133 def cmd_pass(self, arg):
134 self.push('230 password ok')
135
136 def cmd_acct(self, arg):
137 self.push('230 acct ok')
138
139 def cmd_rnfr(self, arg):
140 self.push('350 rnfr ok')
141
142 def cmd_rnto(self, arg):
143 self.push('250 rnto ok')
144
145 def cmd_dele(self, arg):
146 self.push('250 dele ok')
147
148 def cmd_cwd(self, arg):
149 self.push('250 cwd ok')
150
151 def cmd_size(self, arg):
152 self.push('250 1000')
153
154 def cmd_mkd(self, arg):
155 self.push('257 "%s"' %arg)
156
157 def cmd_rmd(self, arg):
158 self.push('250 rmd ok')
159
160 def cmd_pwd(self, arg):
161 self.push('257 "pwd ok"')
162
163 def cmd_type(self, arg):
164 self.push('200 type ok')
165
166 def cmd_quit(self, arg):
167 self.push('221 quit ok')
168 self.close()
169
170 def cmd_stor(self, arg):
171 self.push('125 stor ok')
172
173 def cmd_retr(self, arg):
174 self.push('125 retr ok')
175 self.dtp.push(RETR_DATA)
176 self.dtp.close_when_done()
177
178 def cmd_list(self, arg):
179 self.push('125 list ok')
180 self.dtp.push(LIST_DATA)
181 self.dtp.close_when_done()
182
183 def cmd_nlst(self, arg):
184 self.push('125 nlst ok')
185 self.dtp.push(NLST_DATA)
186 self.dtp.close_when_done()
187
188
189class DummyFTPServer(asyncore.dispatcher, threading.Thread):
190
191 handler = DummyFTPHandler
192
193 def __init__(self, address, af=socket.AF_INET):
194 threading.Thread.__init__(self)
195 asyncore.dispatcher.__init__(self)
196 self.create_socket(af, socket.SOCK_STREAM)
197 self.bind(address)
198 self.listen(5)
199 self.active = False
200 self.active_lock = threading.Lock()
201 self.host, self.port = self.socket.getsockname()[:2]
202
203 def start(self):
204 assert not self.active
205 self.__flag = threading.Event()
206 threading.Thread.start(self)
207 self.__flag.wait()
208
209 def run(self):
210 self.active = True
211 self.__flag.set()
212 while self.active and asyncore.socket_map:
213 self.active_lock.acquire()
214 asyncore.loop(timeout=0.1, count=1)
215 self.active_lock.release()
216 asyncore.close_all(ignore_all=True)
217
218 def stop(self):
219 assert self.active
220 self.active = False
221 self.join()
222
223 def handle_accept(self):
224 conn, addr = self.accept()
225 self.handler = self.handler(conn)
Benjamin Petersond06e3b02008-09-28 21:00:42 +0000226 self.close()
227
228 def handle_connect(self):
229 self.close()
230 handle_read = handle_connect
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000231
232 def writable(self):
233 return 0
234
235 def handle_error(self):
236 raise
237
238
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000239if ssl is not None:
240
241 CERTFILE = os.path.join(os.path.dirname(__file__), "keycert.pem")
242
243 class SSLConnection(asyncore.dispatcher):
244 """An asyncore.dispatcher subclass supporting TLS/SSL."""
245
246 _ssl_accepting = False
247
248 def secure_connection(self):
249 self.del_channel()
250 socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False,
251 certfile=CERTFILE, server_side=True,
252 do_handshake_on_connect=False,
253 ssl_version=ssl.PROTOCOL_SSLv23)
254 self.set_socket(socket)
255 self._ssl_accepting = True
256
257 def _do_ssl_handshake(self):
258 try:
259 self.socket.do_handshake()
260 except ssl.SSLError as err:
261 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
262 ssl.SSL_ERROR_WANT_WRITE):
263 return
264 elif err.args[0] == ssl.SSL_ERROR_EOF:
265 return self.handle_close()
266 raise
267 except socket.error as err:
268 if err.args[0] == errno.ECONNABORTED:
269 return self.handle_close()
270 else:
271 self._ssl_accepting = False
272
273 def handle_read_event(self):
274 if self._ssl_accepting:
275 self._do_ssl_handshake()
276 else:
277 super(SSLConnection, self).handle_read_event()
278
279 def handle_write_event(self):
280 if self._ssl_accepting:
281 self._do_ssl_handshake()
282 else:
283 super(SSLConnection, self).handle_write_event()
284
285 def send(self, data):
286 try:
287 return super(SSLConnection, self).send(data)
288 except ssl.SSLError as err:
289 if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN):
290 return 0
291 raise
292
293 def recv(self, buffer_size):
294 try:
295 return super(SSLConnection, self).recv(buffer_size)
296 except ssl.SSLError as err:
297 if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN):
298 self.handle_close()
299 return b''
300 raise
301
302 def handle_error(self):
303 raise
304
305 def close(self):
306 try:
307 if isinstance(self.socket, ssl.SSLSocket):
308 if self.socket._sslobj is not None:
309 self.socket.unwrap()
310 finally:
311 super(SSLConnection, self).close()
312
313
314 class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler):
315 """A DummyDTPHandler subclass supporting TLS/SSL."""
316
317 def __init__(self, conn, baseclass):
318 DummyDTPHandler.__init__(self, conn, baseclass)
319 if self.baseclass.secure_data_channel:
320 self.secure_connection()
321
322
323 class DummyTLS_FTPHandler(SSLConnection, DummyFTPHandler):
324 """A DummyFTPHandler subclass supporting TLS/SSL."""
325
326 dtp_handler = DummyTLS_DTPHandler
327
328 def __init__(self, conn):
329 DummyFTPHandler.__init__(self, conn)
330 self.secure_data_channel = False
331
332 def cmd_auth(self, line):
333 """Set up secure control channel."""
334 self.push('234 AUTH TLS successful')
335 self.secure_connection()
336
337 def cmd_pbsz(self, line):
338 """Negotiate size of buffer for secure data transfer.
339 For TLS/SSL the only valid value for the parameter is '0'.
340 Any other value is accepted but ignored.
341 """
342 self.push('200 PBSZ=0 successful.')
343
344 def cmd_prot(self, line):
345 """Setup un/secure data channel."""
346 arg = line.upper()
347 if arg == 'C':
348 self.push('200 Protection set to Clear')
349 self.secure_data_channel = False
350 elif arg == 'P':
351 self.push('200 Protection set to Private')
352 self.secure_data_channel = True
353 else:
354 self.push("502 Unrecognized PROT type (use C or P).")
355
356
357 class DummyTLS_FTPServer(DummyFTPServer):
358 handler = DummyTLS_FTPHandler
359
360
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000361class TestFTPClass(TestCase):
362
363 def setUp(self):
364 self.server = DummyFTPServer((HOST, 0))
365 self.server.start()
366 self.client = ftplib.FTP(timeout=2)
367 self.client.connect(self.server.host, self.server.port)
368
369 def tearDown(self):
370 self.client.close()
371 self.server.stop()
372
373 def test_getwelcome(self):
374 self.assertEqual(self.client.getwelcome(), '220 welcome')
375
376 def test_sanitize(self):
377 self.assertEqual(self.client.sanitize('foo'), repr('foo'))
378 self.assertEqual(self.client.sanitize('pass 12345'), repr('pass *****'))
379 self.assertEqual(self.client.sanitize('PASS 12345'), repr('PASS *****'))
380
381 def test_exceptions(self):
382 self.assertRaises(ftplib.error_temp, self.client.sendcmd, 'echo 400')
383 self.assertRaises(ftplib.error_temp, self.client.sendcmd, 'echo 499')
384 self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'echo 500')
385 self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'echo 599')
386 self.assertRaises(ftplib.error_proto, self.client.sendcmd, 'echo 999')
387
388 def test_all_errors(self):
389 exceptions = (ftplib.error_reply, ftplib.error_temp, ftplib.error_perm,
390 ftplib.error_proto, ftplib.Error, IOError, EOFError)
391 for x in exceptions:
392 try:
393 raise x('exception not included in all_errors set')
394 except ftplib.all_errors:
395 pass
396
397 def test_set_pasv(self):
398 # passive mode is supposed to be enabled by default
399 self.assertTrue(self.client.passiveserver)
400 self.client.set_pasv(True)
401 self.assertTrue(self.client.passiveserver)
402 self.client.set_pasv(False)
403 self.assertFalse(self.client.passiveserver)
404
405 def test_voidcmd(self):
406 self.client.voidcmd('echo 200')
407 self.client.voidcmd('echo 299')
408 self.assertRaises(ftplib.error_reply, self.client.voidcmd, 'echo 199')
409 self.assertRaises(ftplib.error_reply, self.client.voidcmd, 'echo 300')
410
411 def test_login(self):
412 self.client.login()
413
414 def test_acct(self):
415 self.client.acct('passwd')
416
417 def test_rename(self):
418 self.client.rename('a', 'b')
419 self.server.handler.next_response = '200'
420 self.assertRaises(ftplib.error_reply, self.client.rename, 'a', 'b')
421
422 def test_delete(self):
423 self.client.delete('foo')
424 self.server.handler.next_response = '199'
425 self.assertRaises(ftplib.error_reply, self.client.delete, 'foo')
426
427 def test_size(self):
428 self.client.size('foo')
429
430 def test_mkd(self):
431 dir = self.client.mkd('/foo')
432 self.assertEqual(dir, '/foo')
433
434 def test_rmd(self):
435 self.client.rmd('foo')
436
437 def test_pwd(self):
438 dir = self.client.pwd()
439 self.assertEqual(dir, 'pwd ok')
440
441 def test_quit(self):
442 self.assertEqual(self.client.quit(), '221 quit ok')
443 # Ensure the connection gets closed; sock attribute should be None
444 self.assertEqual(self.client.sock, None)
445
446 def test_retrbinary(self):
447 def callback(data):
448 received.append(data.decode('ascii'))
449 received = []
450 self.client.retrbinary('retr', callback)
451 self.assertEqual(''.join(received), RETR_DATA)
452
453 def test_retrlines(self):
454 received = []
455 self.client.retrlines('retr', received.append)
456 self.assertEqual(''.join(received), RETR_DATA.replace('\r\n', ''))
457
458 def test_storbinary(self):
459 f = io.BytesIO(RETR_DATA.encode('ascii'))
460 self.client.storbinary('stor', f)
461 self.assertEqual(self.server.handler.last_received_data, RETR_DATA)
462 # test new callback arg
463 flag = []
464 f.seek(0)
465 self.client.storbinary('stor', f, callback=lambda x: flag.append(None))
466 self.assertTrue(flag)
467
468 def test_storlines(self):
469 f = io.BytesIO(RETR_DATA.replace('\r\n', '\n').encode('ascii'))
470 self.client.storlines('stor', f)
471 self.assertEqual(self.server.handler.last_received_data, RETR_DATA)
472 # test new callback arg
473 flag = []
474 f.seek(0)
475 self.client.storlines('stor foo', f, callback=lambda x: flag.append(None))
476 self.assertTrue(flag)
477
478 def test_nlst(self):
479 self.client.nlst()
480 self.assertEqual(self.client.nlst(), NLST_DATA.split('\r\n')[:-1])
481
482 def test_dir(self):
483 l = []
484 self.client.dir(lambda x: l.append(x))
485 self.assertEqual(''.join(l), LIST_DATA.replace('\r\n', ''))
486
Benjamin Peterson3a53fbb2008-09-27 22:04:16 +0000487 def test_makeport(self):
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000488 self.client.makeport()
489 # IPv4 is in use, just make sure send_eprt has not been used
490 self.assertEqual(self.server.handler.last_received_cmd, 'port')
491
492 def test_makepasv(self):
493 host, port = self.client.makepasv()
494 conn = socket.create_connection((host, port), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000495 conn.close()
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000496 # IPv4 is in use, just make sure send_epsv has not been used
497 self.assertEqual(self.server.handler.last_received_cmd, 'pasv')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000498
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000499
500class TestIPv6Environment(TestCase):
501
502 def setUp(self):
503 self.server = DummyFTPServer((HOST, 0), af=socket.AF_INET6)
504 self.server.start()
505 self.client = ftplib.FTP()
506 self.client.connect(self.server.host, self.server.port)
507
508 def tearDown(self):
509 self.client.close()
510 self.server.stop()
511
512 def test_af(self):
513 self.assertEqual(self.client.af, socket.AF_INET6)
514
515 def test_makeport(self):
516 self.client.makeport()
517 self.assertEqual(self.server.handler.last_received_cmd, 'eprt')
518
519 def test_makepasv(self):
520 host, port = self.client.makepasv()
521 conn = socket.create_connection((host, port), 2)
522 conn.close()
523 self.assertEqual(self.server.handler.last_received_cmd, 'epsv')
524
525 def test_transfer(self):
526 def retr():
527 def callback(data):
528 received.append(data.decode('ascii'))
529 received = []
530 self.client.retrbinary('retr', callback)
531 self.assertEqual(''.join(received), RETR_DATA)
532 self.client.set_pasv(True)
533 retr()
534 self.client.set_pasv(False)
535 retr()
536
537
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000538class TestTLS_FTPClassMixin(TestFTPClass):
539 """Repeat TestFTPClass tests starting the TLS layer for both control
540 and data connections first.
541 """
542
543 def setUp(self):
544 self.server = DummyTLS_FTPServer((HOST, 0))
545 self.server.start()
546 self.client = ftplib.FTP_TLS(timeout=2)
547 self.client.connect(self.server.host, self.server.port)
548 # enable TLS
549 self.client.auth()
550 self.client.prot_p()
551
552
553class TestTLS_FTPClass(TestCase):
554 """Specific TLS_FTP class tests."""
555
556 def setUp(self):
557 self.server = DummyTLS_FTPServer((HOST, 0))
558 self.server.start()
559 self.client = ftplib.FTP_TLS(timeout=2)
560 self.client.connect(self.server.host, self.server.port)
561
562 def tearDown(self):
563 self.client.close()
564 self.server.stop()
565
566 def test_control_connection(self):
567 self.assertFalse(isinstance(self.client.sock, ssl.SSLSocket))
568 self.client.auth()
569 self.assertTrue(isinstance(self.client.sock, ssl.SSLSocket))
570
571 def test_data_connection(self):
572 # clear text
573 sock = self.client.transfercmd('list')
574 self.assertFalse(isinstance(sock, ssl.SSLSocket))
575 sock.close()
576 self.client.voidresp()
577
578 # secured, after PROT P
579 self.client.prot_p()
580 sock = self.client.transfercmd('list')
581 self.assertTrue(isinstance(sock, ssl.SSLSocket))
582 sock.close()
583 self.client.voidresp()
584
585 # PROT C is issued, the connection must be in cleartext again
586 self.client.prot_c()
587 sock = self.client.transfercmd('list')
588 self.assertFalse(isinstance(sock, ssl.SSLSocket))
589 sock.close()
590 self.client.voidresp()
591
592 def test_login(self):
593 # login() is supposed to implicitly secure the control connection
594 self.assertFalse(isinstance(self.client.sock, ssl.SSLSocket))
595 self.client.login()
596 self.assertTrue(isinstance(self.client.sock, ssl.SSLSocket))
597 # make sure that AUTH TLS doesn't get issued again
598 self.client.login()
599
600 def test_auth_issued_twice(self):
601 self.client.auth()
602 self.assertRaises(ValueError, self.client.auth)
603
604 def test_auth_ssl(self):
605 try:
606 self.client.ssl_version = ssl.PROTOCOL_SSLv3
607 self.client.auth()
608 self.assertRaises(ValueError, self.client.auth)
609 finally:
610 self.client.ssl_version = ssl.PROTOCOL_TLSv1
611
612
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000613class TestTimeouts(TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000614
615 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000616 self.evt = threading.Event()
Christian Heimes5e696852008-04-09 08:37:03 +0000617 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
618 self.sock.settimeout(3)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000619 self.port = support.bind_port(self.sock)
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000620 threading.Thread(target=self.server, args=(self.evt,self.sock)).start()
Christian Heimes836baa52008-02-26 08:18:30 +0000621 # Wait for the server to be ready.
622 self.evt.wait()
623 self.evt.clear()
Christian Heimes5e696852008-04-09 08:37:03 +0000624 ftplib.FTP.port = self.port
Guido van Rossumd8faa362007-04-27 19:54:29 +0000625
626 def tearDown(self):
627 self.evt.wait()
628
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000629 def server(self, evt, serv):
630 # This method sets the evt 3 times:
631 # 1) when the connection is ready to be accepted.
632 # 2) when it is safe for the caller to close the connection
633 # 3) when we have closed the socket
634 serv.listen(5)
635 # (1) Signal the caller that we are ready to accept the connection.
636 evt.set()
637 try:
638 conn, addr = serv.accept()
639 except socket.timeout:
640 pass
641 else:
642 conn.send(b"1 Hola mundo\n")
643 # (2) Signal the caller that it is safe to close the socket.
644 evt.set()
645 conn.close()
646 finally:
647 serv.close()
648 # (3) Signal the caller that we are done.
649 evt.set()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000650
651 def testTimeoutDefault(self):
Georg Brandlf78e02b2008-06-10 17:40:04 +0000652 # default -- use global socket timeout
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000653 self.assertTrue(socket.getdefaulttimeout() is None)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000654 socket.setdefaulttimeout(30)
655 try:
656 ftp = ftplib.FTP("localhost")
657 finally:
658 socket.setdefaulttimeout(None)
659 self.assertEqual(ftp.sock.gettimeout(), 30)
660 self.evt.wait()
661 ftp.close()
662
663 def testTimeoutNone(self):
664 # no timeout -- do not use global socket timeout
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000665 self.assertTrue(socket.getdefaulttimeout() is None)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000666 socket.setdefaulttimeout(30)
667 try:
668 ftp = ftplib.FTP("localhost", timeout=None)
669 finally:
670 socket.setdefaulttimeout(None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000671 self.assertTrue(ftp.sock.gettimeout() is None)
Christian Heimes836baa52008-02-26 08:18:30 +0000672 self.evt.wait()
Georg Brandlf78e02b2008-06-10 17:40:04 +0000673 ftp.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000674
675 def testTimeoutValue(self):
676 # a value
Christian Heimes5e696852008-04-09 08:37:03 +0000677 ftp = ftplib.FTP(HOST, timeout=30)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000678 self.assertEqual(ftp.sock.gettimeout(), 30)
Christian Heimes836baa52008-02-26 08:18:30 +0000679 self.evt.wait()
Georg Brandlf78e02b2008-06-10 17:40:04 +0000680 ftp.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000681
682 def testTimeoutConnect(self):
683 ftp = ftplib.FTP()
Christian Heimes5e696852008-04-09 08:37:03 +0000684 ftp.connect(HOST, timeout=30)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000685 self.assertEqual(ftp.sock.gettimeout(), 30)
Christian Heimes836baa52008-02-26 08:18:30 +0000686 self.evt.wait()
Georg Brandlf78e02b2008-06-10 17:40:04 +0000687 ftp.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000688
689 def testTimeoutDifferentOrder(self):
690 ftp = ftplib.FTP(timeout=30)
Christian Heimes5e696852008-04-09 08:37:03 +0000691 ftp.connect(HOST)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000692 self.assertEqual(ftp.sock.gettimeout(), 30)
Christian Heimes836baa52008-02-26 08:18:30 +0000693 self.evt.wait()
Georg Brandlf78e02b2008-06-10 17:40:04 +0000694 ftp.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000695
696 def testTimeoutDirectAccess(self):
697 ftp = ftplib.FTP()
698 ftp.timeout = 30
Christian Heimes5e696852008-04-09 08:37:03 +0000699 ftp.connect(HOST)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000700 self.assertEqual(ftp.sock.gettimeout(), 30)
Christian Heimes836baa52008-02-26 08:18:30 +0000701 self.evt.wait()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000702 ftp.close()
703
704
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000705def test_main():
706 tests = [TestFTPClass, TestTimeouts]
707 if socket.has_ipv6:
708 try:
709 DummyFTPServer((HOST, 0), af=socket.AF_INET6)
710 except socket.error:
711 pass
712 else:
713 tests.append(TestIPv6Environment)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000714
715 if ssl is not None:
716 tests.extend([TestTLS_FTPClassMixin, TestTLS_FTPClass])
717
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000718 thread_info = support.threading_setup()
719 try:
720 support.run_unittest(*tests)
721 finally:
722 support.threading_cleanup(*thread_info)
723
Guido van Rossumd8faa362007-04-27 19:54:29 +0000724
725if __name__ == '__main__':
726 test_main()