| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python | 
 | 2 |  | 
 | 3 | import unittest | 
 | 4 | from test import test_support | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 5 | from test.test_urllib2 import sanepathname2url | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 6 |  | 
 | 7 | import socket | 
 | 8 | import urllib2 | 
 | 9 | import sys | 
 | 10 | import os | 
 | 11 | import mimetools | 
 | 12 |  | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 13 |  | 
 | 14 | def _urlopen_with_retry(host, *args, **kwargs): | 
 | 15 |     # Connecting to remote hosts is flaky.  Make it more robust | 
 | 16 |     # by retrying the connection several times. | 
 | 17 |     for i in range(3): | 
 | 18 |         try: | 
 | 19 |             return urllib2.urlopen(host, *args, **kwargs) | 
 | 20 |         except urllib2.URLError, last_exc: | 
 | 21 |             continue | 
 | 22 |         except: | 
 | 23 |             raise | 
 | 24 |     raise last_exc | 
 | 25 |  | 
 | 26 |  | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 27 | class URLTimeoutTest(unittest.TestCase): | 
 | 28 |  | 
 | 29 |     TIMEOUT = 10.0 | 
 | 30 |  | 
 | 31 |     def setUp(self): | 
 | 32 |         socket.setdefaulttimeout(self.TIMEOUT) | 
 | 33 |  | 
 | 34 |     def tearDown(self): | 
 | 35 |         socket.setdefaulttimeout(None) | 
 | 36 |  | 
 | 37 |     def testURLread(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 38 |         f = _urlopen_with_retry("http://www.python.org/") | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 39 |         x = f.read() | 
 | 40 |  | 
| Georg Brandl | fa42bd7 | 2006-04-30 07:06:11 +0000 | [diff] [blame] | 41 |  | 
 | 42 | class AuthTests(unittest.TestCase): | 
 | 43 |     """Tests urllib2 authentication features.""" | 
 | 44 |  | 
 | 45 | ## Disabled at the moment since there is no page under python.org which | 
 | 46 | ## could be used to HTTP authentication. | 
 | 47 | # | 
 | 48 | #    def test_basic_auth(self): | 
 | 49 | #        import httplib | 
 | 50 | # | 
 | 51 | #        test_url = "http://www.python.org/test/test_urllib2/basic_auth" | 
 | 52 | #        test_hostport = "www.python.org" | 
 | 53 | #        test_realm = 'Test Realm' | 
 | 54 | #        test_user = 'test.test_urllib2net' | 
 | 55 | #        test_password = 'blah' | 
 | 56 | # | 
 | 57 | #        # failure | 
 | 58 | #        try: | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 59 | #            _urlopen_with_retry(test_url) | 
| Georg Brandl | fa42bd7 | 2006-04-30 07:06:11 +0000 | [diff] [blame] | 60 | #        except urllib2.HTTPError, exc: | 
 | 61 | #            self.assertEqual(exc.code, 401) | 
 | 62 | #        else: | 
 | 63 | #            self.fail("urlopen() should have failed with 401") | 
 | 64 | # | 
 | 65 | #        # success | 
 | 66 | #        auth_handler = urllib2.HTTPBasicAuthHandler() | 
 | 67 | #        auth_handler.add_password(test_realm, test_hostport, | 
 | 68 | #                                  test_user, test_password) | 
 | 69 | #        opener = urllib2.build_opener(auth_handler) | 
 | 70 | #        f = opener.open('http://localhost/') | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 71 | #        response = _urlopen_with_retry("http://www.python.org/") | 
| Georg Brandl | fa42bd7 | 2006-04-30 07:06:11 +0000 | [diff] [blame] | 72 | # | 
 | 73 | #        # The 'userinfo' URL component is deprecated by RFC 3986 for security | 
 | 74 | #        # reasons, let's not implement it!  (it's already implemented for proxy | 
 | 75 | #        # specification strings (that is, URLs or authorities specifying a | 
 | 76 | #        # proxy), so we must keep that) | 
 | 77 | #        self.assertRaises(httplib.InvalidURL, | 
 | 78 | #                          urllib2.urlopen, "http://evil:thing@example.com") | 
 | 79 |  | 
 | 80 |  | 
| Georg Brandl | dd7b052 | 2007-01-21 10:35:10 +0000 | [diff] [blame] | 81 | class CloseSocketTest(unittest.TestCase): | 
 | 82 |  | 
 | 83 |     def test_close(self): | 
 | 84 |         import socket, httplib, gc | 
 | 85 |  | 
 | 86 |         # calling .close() on urllib2's response objects should close the | 
 | 87 |         # underlying socket | 
 | 88 |  | 
 | 89 |         # delve deep into response to fetch socket._socketobject | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 90 |         response = _urlopen_with_retry("http://www.python.org/") | 
| Georg Brandl | dd7b052 | 2007-01-21 10:35:10 +0000 | [diff] [blame] | 91 |         abused_fileobject = response.fp | 
 | 92 |         self.assert_(abused_fileobject.__class__ is socket._fileobject) | 
 | 93 |         httpresponse = abused_fileobject._sock | 
 | 94 |         self.assert_(httpresponse.__class__ is httplib.HTTPResponse) | 
 | 95 |         fileobject = httpresponse.fp | 
 | 96 |         self.assert_(fileobject.__class__ is socket._fileobject) | 
 | 97 |  | 
 | 98 |         self.assert_(not fileobject.closed) | 
 | 99 |         response.close() | 
 | 100 |         self.assert_(fileobject.closed) | 
 | 101 |  | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 102 | class urlopenNetworkTests(unittest.TestCase): | 
 | 103 |     """Tests urllib2.urlopen using the network. | 
 | 104 |  | 
 | 105 |     These tests are not exhaustive.  Assuming that testing using files does a | 
 | 106 |     good job overall of some of the basic interface features.  There are no | 
 | 107 |     tests exercising the optional 'data' and 'proxies' arguments.  No tests | 
 | 108 |     for transparent redirection have been written. | 
 | 109 |  | 
 | 110 |     setUp is not used for always constructing a connection to | 
 | 111 |     http://www.python.org/ since there a few tests that don't use that address | 
 | 112 |     and making a connection is expensive enough to warrant minimizing unneeded | 
 | 113 |     connections. | 
 | 114 |  | 
 | 115 |     """ | 
 | 116 |  | 
 | 117 |     def test_basic(self): | 
 | 118 |         # Simple test expected to pass. | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 119 |         open_url = _urlopen_with_retry("http://www.python.org/") | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 120 |         for attr in ("read", "close", "info", "geturl"): | 
 | 121 |             self.assert_(hasattr(open_url, attr), "object returned from " | 
 | 122 |                             "urlopen lacks the %s attribute" % attr) | 
 | 123 |         try: | 
 | 124 |             self.assert_(open_url.read(), "calling 'read' failed") | 
 | 125 |         finally: | 
 | 126 |             open_url.close() | 
 | 127 |  | 
 | 128 |     def test_info(self): | 
 | 129 |         # Test 'info'. | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 130 |         open_url = _urlopen_with_retry("http://www.python.org/") | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 131 |         try: | 
 | 132 |             info_obj = open_url.info() | 
 | 133 |         finally: | 
 | 134 |             open_url.close() | 
 | 135 |             self.assert_(isinstance(info_obj, mimetools.Message), | 
 | 136 |                          "object returned by 'info' is not an instance of " | 
 | 137 |                          "mimetools.Message") | 
 | 138 |             self.assertEqual(info_obj.getsubtype(), "html") | 
 | 139 |  | 
 | 140 |     def test_geturl(self): | 
 | 141 |         # Make sure same URL as opened is returned by geturl. | 
 | 142 |         URL = "http://www.python.org/" | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 143 |         open_url = _urlopen_with_retry(URL) | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 144 |         try: | 
 | 145 |             gotten_url = open_url.geturl() | 
 | 146 |         finally: | 
 | 147 |             open_url.close() | 
 | 148 |         self.assertEqual(gotten_url, URL) | 
 | 149 |  | 
 | 150 |     def test_bad_address(self): | 
 | 151 |         # Make sure proper exception is raised when connecting to a bogus | 
 | 152 |         # address. | 
 | 153 |         self.assertRaises(IOError, | 
 | 154 |                           # SF patch 809915:  In Sep 2003, VeriSign started | 
 | 155 |                           # highjacking invalid .com and .net addresses to | 
 | 156 |                           # boost traffic to their own site.  This test | 
 | 157 |                           # started failing then.  One hopes the .invalid | 
 | 158 |                           # domain will be spared to serve its defined | 
 | 159 |                           # purpose. | 
 | 160 |                           # urllib2.urlopen, "http://www.sadflkjsasadf.com/") | 
| Neal Norwitz | a29fc29 | 2006-06-11 20:25:56 +0000 | [diff] [blame] | 161 |                           urllib2.urlopen, "http://www.python.invalid./") | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 162 |  | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 163 |  | 
 | 164 | class OtherNetworkTests(unittest.TestCase): | 
 | 165 |     def setUp(self): | 
 | 166 |         if 0:  # for debugging | 
 | 167 |             import logging | 
 | 168 |             logger = logging.getLogger("test_urllib2net") | 
 | 169 |             logger.addHandler(logging.StreamHandler()) | 
 | 170 |  | 
 | 171 |     def test_range (self): | 
 | 172 |         req = urllib2.Request("http://www.python.org", | 
 | 173 |                               headers={'Range': 'bytes=20-39'}) | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 174 |         result = _urlopen_with_retry(req) | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 175 |         data = result.read() | 
 | 176 |         self.assertEqual(len(data), 20) | 
 | 177 |  | 
 | 178 |     # XXX The rest of these tests aren't very good -- they don't check much. | 
 | 179 |     # They do sometimes catch some major disasters, though. | 
 | 180 |  | 
 | 181 |     def test_ftp(self): | 
 | 182 |         urls = [ | 
| Gregory P. Smith | e9fef69 | 2007-09-09 23:36:46 +0000 | [diff] [blame] | 183 |             'ftp://ftp.kernel.org/pub/linux/kernel/README', | 
 | 184 |             'ftp://ftp.kernel.org/pub/linux/kernel/non-existant-file', | 
 | 185 |             #'ftp://ftp.kernel.org/pub/leenox/kernel/test', | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 186 |             'ftp://gatekeeper.research.compaq.com/pub/DEC/SRC' | 
 | 187 |                 '/research-reports/00README-Legal-Rules-Regs', | 
 | 188 |             ] | 
 | 189 |         self._test_urls(urls, self._extra_handlers()) | 
 | 190 |  | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 191 |     def test_file(self): | 
 | 192 |         TESTFN = test_support.TESTFN | 
 | 193 |         f = open(TESTFN, 'w') | 
 | 194 |         try: | 
 | 195 |             f.write('hi there\n') | 
 | 196 |             f.close() | 
 | 197 |             urls = [ | 
 | 198 |                 'file:'+sanepathname2url(os.path.abspath(TESTFN)), | 
| Gregory P. Smith | e9fef69 | 2007-09-09 23:36:46 +0000 | [diff] [blame] | 199 |                 ('file:///nonsensename/etc/passwd', None, urllib2.URLError), | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 200 |                 ] | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 201 |             self._test_urls(urls, self._extra_handlers(), urllib2.urlopen) | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 202 |         finally: | 
 | 203 |             os.remove(TESTFN) | 
 | 204 |  | 
 | 205 |     def test_http(self): | 
 | 206 |         urls = [ | 
 | 207 |             'http://www.espn.com/', # redirect | 
 | 208 |             'http://www.python.org/Spanish/Inquistion/', | 
 | 209 |             ('http://www.python.org/cgi-bin/faqw.py', | 
 | 210 |              'query=pythonistas&querytype=simple&casefold=yes&req=search', None), | 
 | 211 |             'http://www.python.org/', | 
 | 212 |             ] | 
 | 213 |         self._test_urls(urls, self._extra_handlers()) | 
 | 214 |  | 
 | 215 |     # XXX Following test depends on machine configurations that are internal | 
 | 216 |     # to CNRI.  Need to set up a public server with the right authentication | 
 | 217 |     # configuration for test purposes. | 
 | 218 |  | 
 | 219 | ##     def test_cnri(self): | 
 | 220 | ##         if socket.gethostname() == 'bitdiddle': | 
 | 221 | ##             localhost = 'bitdiddle.cnri.reston.va.us' | 
 | 222 | ##         elif socket.gethostname() == 'bitdiddle.concentric.net': | 
 | 223 | ##             localhost = 'localhost' | 
 | 224 | ##         else: | 
 | 225 | ##             localhost = None | 
 | 226 | ##         if localhost is not None: | 
 | 227 | ##             urls = [ | 
 | 228 | ##                 'file://%s/etc/passwd' % localhost, | 
 | 229 | ##                 'http://%s/simple/' % localhost, | 
 | 230 | ##                 'http://%s/digest/' % localhost, | 
 | 231 | ##                 'http://%s/not/found.h' % localhost, | 
 | 232 | ##                 ] | 
 | 233 |  | 
 | 234 | ##             bauth = HTTPBasicAuthHandler() | 
 | 235 | ##             bauth.add_password('basic_test_realm', localhost, 'jhylton', | 
 | 236 | ##                                'password') | 
 | 237 | ##             dauth = HTTPDigestAuthHandler() | 
 | 238 | ##             dauth.add_password('digest_test_realm', localhost, 'jhylton', | 
 | 239 | ##                                'password') | 
 | 240 |  | 
 | 241 | ##             self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) | 
 | 242 |  | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 243 |     def _test_urls(self, urls, handlers, urlopen=_urlopen_with_retry): | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 244 |         import socket | 
 | 245 |         import time | 
 | 246 |         import logging | 
 | 247 |         debug = logging.getLogger("test_urllib2").debug | 
 | 248 |  | 
 | 249 |         urllib2.install_opener(urllib2.build_opener(*handlers)) | 
 | 250 |  | 
 | 251 |         for url in urls: | 
 | 252 |             if isinstance(url, tuple): | 
 | 253 |                 url, req, expected_err = url | 
 | 254 |             else: | 
 | 255 |                 req = expected_err = None | 
 | 256 |             debug(url) | 
 | 257 |             try: | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 258 |                 f = urlopen(url, req) | 
| Gregory P. Smith | e9fef69 | 2007-09-09 23:36:46 +0000 | [diff] [blame] | 259 |             except EnvironmentError, err: | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 260 |                 debug(err) | 
 | 261 |                 if expected_err: | 
| Gregory P. Smith | e9fef69 | 2007-09-09 23:36:46 +0000 | [diff] [blame] | 262 |                     msg = ("Didn't get expected error(s) %s for %s %s, got %s: %s" % | 
 | 263 |                            (expected_err, url, req, type(err), err)) | 
| Neal Norwitz | f054aeb | 2006-06-11 20:42:02 +0000 | [diff] [blame] | 264 |                     self.assert_(isinstance(err, expected_err), msg) | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 265 |             else: | 
| Brett Cannon | ea2835a | 2007-03-14 21:44:15 +0000 | [diff] [blame] | 266 |                 with test_support.transient_internet(): | 
 | 267 |                     buf = f.read() | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 268 |                 f.close() | 
 | 269 |                 debug("read %d bytes" % len(buf)) | 
 | 270 |             debug("******** next url coming up...") | 
 | 271 |             time.sleep(0.1) | 
 | 272 |  | 
 | 273 |     def _extra_handlers(self): | 
 | 274 |         handlers = [] | 
 | 275 |  | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 276 |         cfh = urllib2.CacheFTPHandler() | 
 | 277 |         cfh.setTimeout(1) | 
 | 278 |         handlers.append(cfh) | 
 | 279 |  | 
 | 280 |         return handlers | 
 | 281 |  | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 282 | class TimeoutTest(unittest.TestCase): | 
 | 283 |     def test_http_basic(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 284 |         u = _urlopen_with_retry("http://www.python.org") | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 285 |         self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) | 
 | 286 |  | 
 | 287 |     def test_http_NoneWithdefault(self): | 
 | 288 |         prev = socket.getdefaulttimeout() | 
 | 289 |         socket.setdefaulttimeout(60) | 
 | 290 |         try: | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 291 |             u = _urlopen_with_retry("http://www.python.org", timeout=None) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 292 |             self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60) | 
 | 293 |         finally: | 
 | 294 |             socket.setdefaulttimeout(prev) | 
 | 295 |  | 
 | 296 |     def test_http_Value(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 297 |         u = _urlopen_with_retry("http://www.python.org", timeout=120) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 298 |         self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) | 
 | 299 |  | 
 | 300 |     def test_http_NoneNodefault(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 301 |         u = _urlopen_with_retry("http://www.python.org", timeout=None) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 302 |         self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) | 
 | 303 |  | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 304 |     FTP_HOST = "ftp://ftp.mirror.nl/pub/mirror/gnu/" | 
 | 305 |  | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 306 |     def test_ftp_basic(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 307 |         u = _urlopen_with_retry(self.FTP_HOST) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 308 |         self.assertTrue(u.fp.fp._sock.gettimeout() is None) | 
 | 309 |  | 
 | 310 |     def test_ftp_NoneWithdefault(self): | 
 | 311 |         prev = socket.getdefaulttimeout() | 
 | 312 |         socket.setdefaulttimeout(60) | 
 | 313 |         try: | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 314 |             u = _urlopen_with_retry(self.FTP_HOST, timeout=None) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 315 |             self.assertEqual(u.fp.fp._sock.gettimeout(), 60) | 
 | 316 |         finally: | 
 | 317 |             socket.setdefaulttimeout(prev) | 
 | 318 |  | 
 | 319 |     def test_ftp_NoneNodefault(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 320 |         u = _urlopen_with_retry(self.FTP_HOST, timeout=None) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 321 |         self.assertTrue(u.fp.fp._sock.gettimeout() is None) | 
 | 322 |  | 
 | 323 |     def test_ftp_Value(self): | 
| Neal Norwitz | 769d0ee | 2008-01-25 06:37:23 +0000 | [diff] [blame] | 324 |         u = _urlopen_with_retry(self.FTP_HOST, timeout=60) | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 325 |         self.assertEqual(u.fp.fp._sock.gettimeout(), 60) | 
 | 326 |  | 
| Georg Brandl | 1b06a1d | 2006-05-03 05:15:10 +0000 | [diff] [blame] | 327 |  | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 328 | def test_main(): | 
 | 329 |     test_support.requires("network") | 
| Georg Brandl | dd7b052 | 2007-01-21 10:35:10 +0000 | [diff] [blame] | 330 |     test_support.run_unittest(URLTimeoutTest, | 
 | 331 |                               urlopenNetworkTests, | 
 | 332 |                               AuthTests, | 
 | 333 |                               OtherNetworkTests, | 
 | 334 |                               CloseSocketTest, | 
| Facundo Batista | 10951d5 | 2007-06-06 17:15:23 +0000 | [diff] [blame] | 335 |                               TimeoutTest, | 
| Georg Brandl | dd7b052 | 2007-01-21 10:35:10 +0000 | [diff] [blame] | 336 |                               ) | 
| Jeremy Hylton | 5d9c303 | 2004-08-07 17:40:50 +0000 | [diff] [blame] | 337 |  | 
 | 338 | if __name__ == "__main__": | 
 | 339 |     test_main() |