blob: 4e9bfb36b15b768ce979897a23cadf0150d45a18 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
5from test import test_support
6import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
11import os
12import pprint
Thomas Wouters1b7f8912007-09-19 03:06:30 +000013import urllib, urlparse
Thomas Woutersed03b412007-08-28 21:37:11 +000014import shutil
15import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000016import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000017
Thomas Wouters1b7f8912007-09-19 03:06:30 +000018from BaseHTTPServer import HTTPServer
19from SimpleHTTPServer import SimpleHTTPRequestHandler
20
Thomas Woutersed03b412007-08-28 21:37:11 +000021# Optionally test SSL support, if we have it in the tested platform
22skip_expected = False
23try:
24 import ssl
25except ImportError:
26 skip_expected = True
27
28CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000029SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000030
Thomas Wouters1b7f8912007-09-19 03:06:30 +000031TESTPORT = 10025
Thomas Woutersed03b412007-08-28 21:37:11 +000032
33def handle_error(prefix):
34 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Thomas Wouters1b7f8912007-09-19 03:06:30 +000035 if test_support.verbose:
36 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000037
38
39class BasicTests(unittest.TestCase):
40
Georg Brandlfceab5a2008-01-19 20:08:23 +000041 def testSSLconnect(self):
42 if not test_support.is_resource_enabled('network'):
43 return
44 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
45 cert_reqs=ssl.CERT_NONE)
46 s.connect(("svn.python.org", 443))
47 c = s.getpeercert()
48 if c:
49 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
50 s.close()
51
52 # this should fail because we have no verification certs
53 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
54 cert_reqs=ssl.CERT_REQUIRED)
55 try:
56 s.connect(("svn.python.org", 443))
57 except ssl.SSLError:
58 pass
59 finally:
60 s.close()
61
Thomas Wouters1b7f8912007-09-19 03:06:30 +000062 def testCrucialConstants(self):
63 ssl.PROTOCOL_SSLv2
64 ssl.PROTOCOL_SSLv23
65 ssl.PROTOCOL_SSLv3
66 ssl.PROTOCOL_TLSv1
67 ssl.CERT_NONE
68 ssl.CERT_OPTIONAL
69 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000070
Thomas Wouters1b7f8912007-09-19 03:06:30 +000071 def testRAND(self):
72 v = ssl.RAND_status()
73 if test_support.verbose:
74 sys.stdout.write("\n RAND_status is %d (%s)\n"
75 % (v, (v and "sufficient randomness") or
76 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000077 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000078 ssl.RAND_egd(1)
79 except TypeError:
80 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000081 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000082 print("didn't raise TypeError")
83 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000084
Thomas Wouters1b7f8912007-09-19 03:06:30 +000085 def testParseCert(self):
86 # note that this uses an 'unofficial' function in _ssl.c,
87 # provided solely for this test, to exercise the certificate
88 # parsing code
89 p = ssl._ssl._test_decode_cert(CERTFILE, False)
90 if test_support.verbose:
91 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000092
Thomas Wouters1b7f8912007-09-19 03:06:30 +000093 def testDERtoPEM(self):
94
95 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
96 d1 = ssl.PEM_cert_to_DER_cert(pem)
97 p2 = ssl.DER_cert_to_PEM_cert(d1)
98 d2 = ssl.PEM_cert_to_DER_cert(p2)
99 if (d1 != d2):
100 raise test_support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
101
Bill Janssen6e027db2007-11-15 22:23:56 +0000102class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000103
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000104 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000105 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
106 cert_reqs=ssl.CERT_NONE)
107 s.connect(("svn.python.org", 443))
108 c = s.getpeercert()
109 if c:
110 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
111 s.close()
112
113 # this should fail because we have no verification certs
114 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
115 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000116 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000117 s.connect(("svn.python.org", 443))
118 except ssl.SSLError:
119 pass
120 finally:
121 s.close()
122
123 # this should succeed because we specify the root cert
124 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
125 cert_reqs=ssl.CERT_REQUIRED,
126 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
127 try:
128 s.connect(("svn.python.org", 443))
129 except ssl.SSLError as x:
130 raise test_support.TestFailed("Unexpected exception %s" % x)
131 finally:
132 s.close()
133
Bill Janssen6e027db2007-11-15 22:23:56 +0000134 def testNonBlockingHandshake(self):
135 s = socket.socket(socket.AF_INET)
136 s.connect(("svn.python.org", 443))
137 s.setblocking(False)
138 s = ssl.wrap_socket(s,
139 cert_reqs=ssl.CERT_NONE,
140 do_handshake_on_connect=False)
141 count = 0
142 while True:
143 try:
144 count += 1
145 s.do_handshake()
146 break
147 except ssl.SSLError as err:
148 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
149 select.select([s], [], [])
150 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
151 select.select([], [s], [])
152 else:
153 raise
154 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155 if test_support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000156 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000157
Bill Janssen54cc54c2007-12-14 22:08:56 +0000158 def testFetchServerCert(self):
159
160 pem = ssl.get_server_certificate(("svn.python.org", 443))
161 if not pem:
162 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
163
164 return
165
166 try:
167 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
168 except ssl.SSLError as x:
169 #should fail
170 if test_support.verbose:
171 sys.stdout.write("%s\n" % x)
172 else:
173 raise test_support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
174
175 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
176 if not pem:
177 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
178 if test_support.verbose:
179 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
180
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000181
182try:
183 import threading
184except ImportError:
185 _have_threads = False
186else:
187
188 _have_threads = True
189
190 class ThreadedEchoServer(threading.Thread):
191
192 class ConnectionHandler(threading.Thread):
193
194 """A mildly complicated class, because we want it to work both
195 with and without the SSL wrapper around the socket connection, so
196 that we can test the STARTTLS functionality."""
197
Bill Janssen6e027db2007-11-15 22:23:56 +0000198 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000199 self.server = server
200 self.running = False
201 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000202 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000203 self.sock.setblocking(1)
204 self.sslconn = None
205 threading.Thread.__init__(self)
206 self.setDaemon(True)
207
208 def wrap_conn (self):
209 try:
210 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
211 certfile=self.server.certificate,
212 ssl_version=self.server.protocol,
213 ca_certs=self.server.cacerts,
214 cert_reqs=self.server.certreqs)
215 except:
216 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000217 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000218 if not self.server.expect_bad_connects:
219 # here, we want to stop the server, because this shouldn't
220 # happen in the context of our test case
221 self.running = False
222 # normally, we'd just stop here, but for the test
223 # harness, we want to stop the server
224 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000225 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000226 return False
227
228 else:
229 if self.server.certreqs == ssl.CERT_REQUIRED:
230 cert = self.sslconn.getpeercert()
231 if test_support.verbose and self.server.chatty:
232 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
233 cert_binary = self.sslconn.getpeercert(True)
234 if test_support.verbose and self.server.chatty:
235 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
236 cipher = self.sslconn.cipher()
237 if test_support.verbose and self.server.chatty:
238 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
239 return True
240
241 def read(self):
242 if self.sslconn:
243 return self.sslconn.read()
244 else:
245 return self.sock.recv(1024)
246
247 def write(self, bytes):
248 if self.sslconn:
249 return self.sslconn.write(bytes)
250 else:
251 return self.sock.send(bytes)
252
253 def close(self):
254 if self.sslconn:
255 self.sslconn.close()
256 else:
257 self.sock.close()
258
259 def run (self):
260 self.running = True
261 if not self.server.starttls_server:
262 if not self.wrap_conn():
263 return
264 while self.running:
265 try:
266 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000267 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000268 if not msg:
269 # eof, so quit this handler
270 self.running = False
271 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000272 elif amsg.strip() == 'over':
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000273 if test_support.verbose and self.server.connectionchatty:
274 sys.stdout.write(" server: client closed connection\n")
275 self.close()
276 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000277 elif (self.server.starttls_server and
278 amsg.strip() == 'STARTTLS'):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000279 if test_support.verbose and self.server.connectionchatty:
280 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000281 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000282 if not self.wrap_conn():
283 return
284 else:
285 if (test_support.verbose and
286 self.server.connectionchatty):
287 ctype = (self.sslconn and "encrypted") or "unencrypted"
288 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
289 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000290 self.write(amsg.lower().encode('ASCII', 'strict'))
291 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000292 if self.server.chatty:
293 handle_error("Test server failure:\n")
294 self.close()
295 self.running = False
296 # normally, we'd just stop here, but for the test
297 # harness, we want to stop the server
298 self.server.stop()
299 except:
300 handle_error('')
301
302 def __init__(self, port, certificate, ssl_version=None,
303 certreqs=None, cacerts=None, expect_bad_connects=False,
304 chatty=True, connectionchatty=False, starttls_server=False):
305 if ssl_version is None:
306 ssl_version = ssl.PROTOCOL_TLSv1
307 if certreqs is None:
308 certreqs = ssl.CERT_NONE
309 self.certificate = certificate
310 self.protocol = ssl_version
311 self.certreqs = certreqs
312 self.cacerts = cacerts
313 self.expect_bad_connects = expect_bad_connects
314 self.chatty = chatty
315 self.connectionchatty = connectionchatty
316 self.starttls_server = starttls_server
317 self.sock = socket.socket()
318 self.flag = None
319 if hasattr(socket, 'SO_REUSEADDR'):
320 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
321 if hasattr(socket, 'SO_REUSEPORT'):
322 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
323 self.sock.bind(('127.0.0.1', port))
324 self.active = False
325 threading.Thread.__init__(self)
326 self.setDaemon(False)
327
328 def start (self, flag=None):
329 self.flag = flag
330 threading.Thread.start(self)
331
332 def run (self):
333 self.sock.settimeout(0.5)
334 self.sock.listen(5)
335 self.active = True
336 if self.flag:
337 # signal an event
338 self.flag.set()
339 while self.active:
340 try:
341 newconn, connaddr = self.sock.accept()
342 if test_support.verbose and self.chatty:
343 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000344 + repr(connaddr) + '\n')
345 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 handler.start()
347 except socket.timeout:
348 pass
349 except KeyboardInterrupt:
350 self.stop()
351 except:
352 if self.chatty:
353 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000354 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355
356 def stop (self):
357 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358
Bill Janssen54cc54c2007-12-14 22:08:56 +0000359 class OurHTTPSServer(threading.Thread):
360
361 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000362
363 class HTTPSServer(HTTPServer):
364
365 def __init__(self, server_address, RequestHandlerClass, certfile):
366
367 HTTPServer.__init__(self, server_address, RequestHandlerClass)
368 # we assume the certfile contains both private key and certificate
369 self.certfile = certfile
370 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000371 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000372 self.allow_reuse_address = True
373
Bill Janssen6e027db2007-11-15 22:23:56 +0000374 def __str__(self):
375 return ('<%s %s:%s>' %
376 (self.__class__.__name__,
377 self.server_name,
378 self.server_port))
379
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000380 def get_request (self):
381 # override this to wrap socket with SSL
382 sock, addr = self.socket.accept()
383 sslconn = ssl.wrap_socket(sock, server_side=True,
384 certfile=self.certfile)
385 return sslconn, addr
386
387 # The methods overridden below this are mainly so that we
388 # can run it in a thread and be able to stop it from another
389 # You probably wouldn't need them in other uses.
390
391 def server_activate(self):
392 # We want to run this in a thread for testing purposes,
393 # so we override this to set timeout, so that we get
394 # a chance to stop the server
395 self.socket.settimeout(0.5)
396 HTTPServer.server_activate(self)
397
398 def serve_forever(self):
399 # We want this to run in a thread, so we use a slightly
400 # modified version of "forever".
401 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000402 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000404 # We need to lock while handling the request.
405 # Another thread can close the socket after self.active
406 # has been checked and before the request is handled.
407 # This causes an exception when using the closed socket.
408 with self.active_lock:
409 if not self.active:
410 break
411 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000412 except socket.timeout:
413 pass
414 except KeyboardInterrupt:
415 self.server_close()
416 return
417 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000418 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
419 break
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000420
421 def server_close(self):
422 # Again, we want this to run in a thread, so we need to override
423 # close to clear the "active" flag, so that serve_forever() will
424 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000425 with self.active_lock:
426 HTTPServer.server_close(self)
427 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000428
429 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
430
431 # need to override translate_path to get a known root,
432 # instead of using os.curdir, since the test could be
433 # run from anywhere
434
435 server_version = "TestHTTPS/1.0"
436
437 root = None
438
439 def translate_path(self, path):
440 """Translate a /-separated PATH to the local filename syntax.
441
442 Components that mean special things to the local file system
443 (e.g. drive or directory names) are ignored. (XXX They should
444 probably be diagnosed.)
445
446 """
447 # abandon query parameters
448 path = urlparse.urlparse(path)[2]
449 path = os.path.normpath(urllib.unquote(path))
450 words = path.split('/')
451 words = filter(None, words)
452 path = self.root
453 for word in words:
454 drive, word = os.path.splitdrive(word)
455 head, word = os.path.split(word)
456 if word in self.root: continue
457 path = os.path.join(path, word)
458 return path
459
460 def log_message(self, format, *args):
461
462 # we override this to suppress logging unless "verbose"
463
Thomas Wouters89d996e2007-09-08 17:39:28 +0000464 if test_support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000465 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
466 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000467 self.server.server_port,
468 self.request.cipher(),
469 self.log_date_time_string(),
470 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000471
472
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000473 def __init__(self, port, certfile):
474 self.flag = None
475 self.active = False
476 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
477 self.server = self.HTTPSServer(
478 ('', port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000479 threading.Thread.__init__(self)
480 self.setDaemon(True)
481
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000482 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000483 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000484
485 def start (self, flag=None):
486 self.flag = flag
487 threading.Thread.start(self)
488
Thomas Woutersed03b412007-08-28 21:37:11 +0000489 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000490 self.active = True
491 if self.flag:
492 self.flag.set()
493 self.server.serve_forever()
494 self.active = False
495
496 def stop (self):
497 self.active = False
498 self.server.server_close()
499
500
Bill Janssen54cc54c2007-12-14 22:08:56 +0000501 class AsyncoreEchoServer(threading.Thread):
502
503 # this one's based on asyncore.dispatcher
504
505 class EchoServer (asyncore.dispatcher):
506
507 class ConnectionHandler (asyncore.dispatcher_with_send):
508
509 def __init__(self, conn, certfile):
510 self.socket = ssl.wrap_socket(conn, server_side=True,
511 certfile=certfile,
512 do_handshake_on_connect=False)
513 asyncore.dispatcher_with_send.__init__(self, self.socket)
514 # now we have to do the handshake
515 # we'll just do it the easy way, and block the connection
516 # till it's finished. If we were doing it right, we'd
517 # do this in multiple calls to handle_read...
518 self.do_handshake(block=True)
519
520 def readable(self):
521 if isinstance(self.socket, ssl.SSLSocket):
522 while self.socket.pending() > 0:
523 self.handle_read_event()
524 return True
525
526 def handle_read(self):
527 data = self.recv(1024)
528 if test_support.verbose:
529 sys.stdout.write(" server: read %s from client\n" % repr(data))
530 if not data:
531 self.close()
532 else:
533 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
534
535 def handle_close(self):
536 if test_support.verbose:
537 sys.stdout.write(" server: closed connection %s\n" % self.socket)
538
539 def handle_error(self):
540 raise
541
542 def __init__(self, port, certfile):
543 self.port = port
544 self.certfile = certfile
545 asyncore.dispatcher.__init__(self)
546 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
547 self.bind(('', port))
548 self.listen(5)
549
550 def handle_accept(self):
551 sock_obj, addr = self.accept()
552 if test_support.verbose:
553 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
554 self.ConnectionHandler(sock_obj, self.certfile)
555
556 def handle_error(self):
557 raise
558
559 def __init__(self, port, certfile):
560 self.flag = None
561 self.active = False
562 self.server = self.EchoServer(port, certfile)
563 threading.Thread.__init__(self)
564 self.setDaemon(True)
565
566 def __str__(self):
567 return "<%s %s>" % (self.__class__.__name__, self.server)
568
569 def start (self, flag=None):
570 self.flag = flag
571 threading.Thread.start(self)
572
573 def run (self):
574 self.active = True
575 if self.flag:
576 self.flag.set()
577 while self.active:
578 try:
579 asyncore.loop(1)
580 except:
581 pass
582
583 def stop (self):
584 self.active = False
585 self.server.close()
586
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000587 def badCertTest (certfile):
588 server = ThreadedEchoServer(TESTPORT, CERTFILE,
589 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000590 cacerts=CERTFILE, chatty=False,
591 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000592 flag = threading.Event()
593 server.start(flag)
594 # wait for it to start
595 flag.wait()
596 # try to connect
597 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000598 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000599 s = ssl.wrap_socket(socket.socket(),
600 certfile=certfile,
601 ssl_version=ssl.PROTOCOL_TLSv1)
602 s.connect(('127.0.0.1', TESTPORT))
603 except ssl.SSLError as x:
Thomas Woutersed03b412007-08-28 21:37:11 +0000604 if test_support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000605 sys.stdout.write("\nSSLError is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000606 else:
607 raise test_support.TestFailed(
608 "Use of invalid cert should have failed!")
609 finally:
610 server.stop()
611 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000612
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000613 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000614 client_certfile, client_protocol=None,
615 indata="FOO\n",
616 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000617
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000618 server = ThreadedEchoServer(TESTPORT, certfile,
619 certreqs=certreqs,
620 ssl_version=protocol,
621 cacerts=cacertsfile,
622 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000623 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000624 flag = threading.Event()
625 server.start(flag)
626 # wait for it to start
627 flag.wait()
628 # try to connect
629 if client_protocol is None:
630 client_protocol = protocol
631 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000632 s = ssl.wrap_socket(socket.socket(),
Bill Janssen54cc54c2007-12-14 22:08:56 +0000633 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000634 certfile=client_certfile,
635 ca_certs=cacertsfile,
636 cert_reqs=certreqs,
637 ssl_version=client_protocol)
638 s.connect(('127.0.0.1', TESTPORT))
639 except ssl.SSLError as x:
640 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
641 except Exception as x:
642 raise test_support.TestFailed("Unexpected exception: " + str(x))
643 else:
644 if connectionchatty:
645 if test_support.verbose:
646 sys.stdout.write(
647 " client: sending %s...\n" % (repr(indata)))
648 s.write(indata.encode('ASCII', 'strict'))
649 outdata = s.read()
650 if connectionchatty:
651 if test_support.verbose:
652 sys.stdout.write(" client: read %s\n" % repr(outdata))
653 outdata = str(outdata, 'ASCII', 'strict')
654 if outdata != indata.lower():
655 raise test_support.TestFailed(
656 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
657 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
658 repr(indata[:min(len(indata),20)].lower()), len(indata)))
659 s.write("over\n".encode("ASCII", "strict"))
660 if connectionchatty:
661 if test_support.verbose:
662 sys.stdout.write(" client: closing connection.\n")
663 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000664 finally:
665 server.stop()
666 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000667
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000668 def tryProtocolCombo (server_protocol,
669 client_protocol,
670 expectedToWork,
671 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000672
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000673 if certsreqs == None:
674 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000675
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000676 if certsreqs == ssl.CERT_NONE:
677 certtype = "CERT_NONE"
678 elif certsreqs == ssl.CERT_OPTIONAL:
679 certtype = "CERT_OPTIONAL"
680 elif certsreqs == ssl.CERT_REQUIRED:
681 certtype = "CERT_REQUIRED"
Thomas Woutersed03b412007-08-28 21:37:11 +0000682 if test_support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000683 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
684 sys.stdout.write(formatstr %
685 (ssl.get_protocol_name(client_protocol),
686 ssl.get_protocol_name(server_protocol),
687 certtype))
688 try:
689 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 CERTFILE, CERTFILE, client_protocol,
691 chatty=False, connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000692 except test_support.TestFailed:
693 if expectedToWork:
694 raise
695 else:
696 if not expectedToWork:
697 raise test_support.TestFailed(
698 "Client protocol %s succeeded with server protocol %s!"
699 % (ssl.get_protocol_name(client_protocol),
700 ssl.get_protocol_name(server_protocol)))
701
702
Bill Janssen6e027db2007-11-15 22:23:56 +0000703 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000704
705 def testEcho (self):
706
707 if test_support.verbose:
708 sys.stdout.write("\n")
709 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
710 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
711 chatty=True, connectionchatty=True)
712
713 def testReadCert(self):
714
715 if test_support.verbose:
716 sys.stdout.write("\n")
717 s2 = socket.socket()
718 server = ThreadedEchoServer(TESTPORT, CERTFILE,
719 certreqs=ssl.CERT_NONE,
720 ssl_version=ssl.PROTOCOL_SSLv23,
721 cacerts=CERTFILE,
722 chatty=False)
723 flag = threading.Event()
724 server.start(flag)
725 # wait for it to start
726 flag.wait()
727 # try to connect
728 try:
729 try:
730 s = ssl.wrap_socket(socket.socket(),
731 certfile=CERTFILE,
732 ca_certs=CERTFILE,
733 cert_reqs=ssl.CERT_REQUIRED,
734 ssl_version=ssl.PROTOCOL_SSLv23)
735 s.connect(('127.0.0.1', TESTPORT))
736 except ssl.SSLError as x:
737 raise test_support.TestFailed(
738 "Unexpected SSL error: " + str(x))
739 except Exception as x:
740 raise test_support.TestFailed(
741 "Unexpected exception: " + str(x))
742 else:
743 if not s:
744 raise test_support.TestFailed(
745 "Can't SSL-handshake with test server")
746 cert = s.getpeercert()
747 if not cert:
748 raise test_support.TestFailed(
749 "Can't get peer certificate.")
750 cipher = s.cipher()
751 if test_support.verbose:
752 sys.stdout.write(pprint.pformat(cert) + '\n')
753 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000754 if 'subject' not in cert:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755 raise test_support.TestFailed(
756 "No subject field in certificate: %s." %
757 pprint.pformat(cert))
758 if ((('organizationName', 'Python Software Foundation'),)
759 not in cert['subject']):
760 raise test_support.TestFailed(
761 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000762 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000763 s.close()
764 finally:
765 server.stop()
766 server.join()
767
768 def testNULLcert(self):
769 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
770 "nullcert.pem"))
771 def testMalformedCert(self):
772 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
773 "badcert.pem"))
774 def testMalformedKey(self):
775 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
776 "badkey.pem"))
777
Bill Janssen6e027db2007-11-15 22:23:56 +0000778 def testRudeShutdown(self):
779
780 listener_ready = threading.Event()
781 listener_gone = threading.Event()
782
783 # `listener` runs in a thread. It opens a socket listening on
784 # PORT, and sits in an accept() until the main thread connects.
785 # Then it rudely closes the socket, and sets Event `listener_gone`
786 # to let the main thread know the socket is gone.
787 def listener():
788 s = socket.socket()
789 if hasattr(socket, 'SO_REUSEADDR'):
790 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
791 if hasattr(socket, 'SO_REUSEPORT'):
792 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
793 s.bind(('127.0.0.1', TESTPORT))
794 s.listen(5)
795 listener_ready.set()
796 s.accept()
797 s = None # reclaim the socket object, which also closes it
798 listener_gone.set()
799
800 def connector():
801 listener_ready.wait()
802 s = socket.socket()
803 s.connect(('127.0.0.1', TESTPORT))
804 listener_gone.wait()
805 try:
806 ssl_sock = ssl.wrap_socket(s)
807 except IOError:
808 pass
809 else:
810 raise test_support.TestFailed(
811 'connecting to closed SSL socket should have failed')
812
813 t = threading.Thread(target=listener)
814 t.start()
815 connector()
816 t.join()
817
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000818 def testProtocolSSL2(self):
819 if test_support.verbose:
820 sys.stdout.write("\n")
821 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
822 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
823 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
824 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
825 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
826 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
827
828 def testProtocolSSL23(self):
829 if test_support.verbose:
830 sys.stdout.write("\n")
831 try:
832 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
833 except test_support.TestFailed as x:
834 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
835 if test_support.verbose:
836 sys.stdout.write(
837 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
838 % str(x))
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
840 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
842
843 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
844 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
845 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
846
847 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
848 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
850
851 def testProtocolSSL3(self):
852 if test_support.verbose:
853 sys.stdout.write("\n")
854 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
855 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
856 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
857 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
858 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
859 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
860
861 def testProtocolTLS1(self):
862 if test_support.verbose:
863 sys.stdout.write("\n")
864 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
865 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
866 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
867 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
868 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
869 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
870
871 def testSTARTTLS (self):
872
873 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
874
875 server = ThreadedEchoServer(TESTPORT, CERTFILE,
876 ssl_version=ssl.PROTOCOL_TLSv1,
877 starttls_server=True,
878 chatty=True,
879 connectionchatty=True)
880 flag = threading.Event()
881 server.start(flag)
882 # wait for it to start
883 flag.wait()
884 # try to connect
885 wrapped = False
886 try:
887 try:
888 s = socket.socket()
889 s.setblocking(1)
890 s.connect(('127.0.0.1', TESTPORT))
891 except Exception as x:
892 raise test_support.TestFailed("Unexpected exception: " + str(x))
893 else:
894 if test_support.verbose:
895 sys.stdout.write("\n")
896 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000897 msg = indata.encode('ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000898 if test_support.verbose:
899 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000900 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000902 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000903 outdata = conn.read()
904 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000905 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 outdata = s.recv(1024)
907 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000908 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 if test_support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000910 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000911 sys.stdout.write(
912 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000913 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000914 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
915
916 wrapped = True
917 else:
918 if test_support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000919 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000920 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000921 " client: read %s from server\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000922 if test_support.verbose:
923 sys.stdout.write(" client: closing connection.\n")
924 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000925 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000926 else:
927 s.send("over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000928 if wrapped:
929 conn.close()
930 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000931 s.close()
932 finally:
933 server.stop()
934 server.join()
935
Bill Janssen54cc54c2007-12-14 22:08:56 +0000936 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000937
Bill Janssen54cc54c2007-12-14 22:08:56 +0000938 server = OurHTTPSServer(TESTPORT, CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000939 flag = threading.Event()
940 server.start(flag)
941 # wait for it to start
942 flag.wait()
943 # try to connect
944 try:
945 if test_support.verbose:
946 sys.stdout.write('\n')
947 d1 = open(CERTFILE, 'rb').read()
948 d2 = ''
949 # now fetch the same data from the HTTPS server
950 url = 'https://127.0.0.1:%d/%s' % (
951 TESTPORT, os.path.split(CERTFILE)[1])
952 f = urllib.urlopen(url)
953 dlen = f.info().getheader("content-length")
954 if dlen and (int(dlen) > 0):
955 d2 = f.read(int(dlen))
956 if test_support.verbose:
957 sys.stdout.write(
958 " client: read %d bytes from remote server '%s'\n"
959 % (len(d2), server))
960 f.close()
961 except:
962 msg = ''.join(traceback.format_exception(*sys.exc_info()))
963 if test_support.verbose:
964 sys.stdout.write('\n' + msg)
965 raise test_support.TestFailed(msg)
966 else:
967 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000968 print("d1 is", len(d1), repr(d1))
969 print("d2 is", len(d2), repr(d2))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000970 raise test_support.TestFailed(
971 "Couldn't fetch data from HTTPS server")
972 finally:
973 server.stop()
974 server.join()
975
Bill Janssen54cc54c2007-12-14 22:08:56 +0000976 def testAsyncoreServer(self):
977
978 if test_support.verbose:
979 sys.stdout.write("\n")
980
981 indata="FOO\n"
982 server = AsyncoreEchoServer(TESTPORT, CERTFILE)
983 flag = threading.Event()
984 server.start(flag)
985 # wait for it to start
986 flag.wait()
987 # try to connect
988 try:
989 s = ssl.wrap_socket(socket.socket())
990 s.connect(('127.0.0.1', TESTPORT))
991 except ssl.SSLError as x:
992 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
993 except Exception as x:
994 raise test_support.TestFailed("Unexpected exception: " + str(x))
995 else:
996 if test_support.verbose:
997 sys.stdout.write(
998 " client: sending %s...\n" % (repr(indata)))
999 s.sendall(indata.encode('ASCII', 'strict'))
1000 outdata = s.recv()
1001 if test_support.verbose:
1002 sys.stdout.write(" client: read %s\n" % repr(outdata))
1003 outdata = str(outdata, 'ASCII', 'strict')
1004 if outdata != indata.lower():
1005 raise test_support.TestFailed(
1006 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1007 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1008 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1009 s.write("over\n".encode("ASCII", "strict"))
1010 if test_support.verbose:
1011 sys.stdout.write(" client: closing connection.\n")
1012 s.close()
1013 finally:
1014 server.stop()
1015 server.join()
1016
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017
1018def findtestsocket(start, end):
1019 def testbind(i):
1020 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1021 try:
1022 s.bind(("127.0.0.1", i))
1023 except:
1024 return 0
1025 else:
1026 return 1
1027 finally:
1028 s.close()
1029
1030 for i in range(start, end):
1031 if testbind(i) and testbind(i+1):
1032 return i
1033 return 0
Thomas Woutersed03b412007-08-28 21:37:11 +00001034
1035
1036def test_main(verbose=False):
1037 if skip_expected:
Thomas Wouters89d996e2007-09-08 17:39:28 +00001038 raise test_support.TestSkipped("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001039
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001040 global CERTFILE, TESTPORT, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001041 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1042 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001043 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1044 os.path.dirname(__file__) or os.curdir,
1045 "https_svn_python_org_root.pem")
1046
1047 if (not os.path.exists(CERTFILE) or
1048 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
1049 raise test_support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001050
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001051 TESTPORT = findtestsocket(10025, 12000)
1052 if not TESTPORT:
1053 raise test_support.TestFailed("Can't find open port to test servers on!")
Thomas Woutersed03b412007-08-28 21:37:11 +00001054
1055 tests = [BasicTests]
1056
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001057 if test_support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001058 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001059
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001060 if _have_threads:
1061 thread_info = test_support.threading_setup()
1062 if thread_info and test_support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001063 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001064
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001065 test_support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001066
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001067 if _have_threads:
1068 test_support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001069
1070if __name__ == "__main__":
1071 test_main()