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