]> granicus.if.org Git - python/commitdiff
Fix the socket tests so they can be run concurrently. Backport candidate
authorNeal Norwitz <nnorwitz@gmail.com>
Mon, 12 Jun 2006 02:13:21 +0000 (02:13 +0000)
committerNeal Norwitz <nnorwitz@gmail.com>
Mon, 12 Jun 2006 02:13:21 +0000 (02:13 +0000)
Lib/test/test_socket.py
Lib/test/test_socket_ssl.py
Lib/test/test_socketserver.py
Lib/test/test_support.py
Misc/NEWS

index 59415aec712e7140de271abc7246a551dd3cd7d3..e0aa58cc1cc84eea53807517c633448f018b1026 100644 (file)
@@ -21,7 +21,8 @@ class SocketTCPTest(unittest.TestCase):
     def setUp(self):
         self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.serv.bind((HOST, PORT))
+        global PORT
+        PORT = test_support.bind_port(self.serv, HOST, PORT)
         self.serv.listen(1)
 
     def tearDown(self):
@@ -33,7 +34,8 @@ class SocketUDPTest(unittest.TestCase):
     def setUp(self):
         self.serv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.serv.bind((HOST, PORT))
+        global PORT
+        PORT = test_support.bind_port(self.serv, HOST, PORT)
 
     def tearDown(self):
         self.serv.close()
index 10913836a8c5f63b11831c7fdb15181958b61e89..074b6279fed6c7a5118ba29bb8871f1a36cb7f24 100644 (file)
@@ -71,7 +71,7 @@ def test_rude_shutdown():
         return
 
     # Some random port to connect to.
-    PORT = 9934
+    PORT = [9934]
 
     listener_ready = threading.Event()
     listener_gone = threading.Event()
@@ -82,7 +82,7 @@ def test_rude_shutdown():
     # know the socket is gone.
     def listener():
         s = socket.socket()
-        s.bind(('', PORT))
+        PORT[0] = test_support.bind_port(s, '', PORT[0])
         s.listen(5)
         listener_ready.set()
         s.accept()
@@ -92,7 +92,7 @@ def test_rude_shutdown():
     def connector():
         listener_ready.wait()
         s = socket.socket()
-        s.connect(('localhost', PORT))
+        s.connect(('localhost', PORT[0]))
         listener_gone.wait()
         try:
             ssl_sock = socket.ssl(s)
index 1245ba5fbf27da9a6216442d58ff7d17aaf6f4b0..93165470f922adc594064c3b5688594047cea0f7 100644 (file)
@@ -6,6 +6,7 @@ test_support.requires('network')
 
 from SocketServer import *
 import socket
+import errno
 import select
 import time
 import threading
@@ -77,6 +78,11 @@ class ServerThread(threading.Thread):
             pass
         if verbose: print "thread: creating server"
         svr = svrcls(self.__addr, self.__hdlrcls)
+        # pull the address out of the server in case it changed
+        # this can happen if another process is using the port
+        addr = getattr(svr, 'server_address')
+        if addr:
+            self.__addr = addr
         if verbose: print "thread: serving three times"
         svr.serve_a_few()
         if verbose: print "thread: done"
@@ -136,7 +142,25 @@ def testloop(proto, servers, hdlrcls, testfunc):
         t.join()
         if verbose: print "done"
 
-tcpservers = [TCPServer, ThreadingTCPServer]
+class ForgivingTCPServer(TCPServer):
+    # prevent errors if another process is using the port we want
+    def server_bind(self):
+        host, default_port = self.server_address
+        # this code shamelessly stolen from test.test_support
+        # the ports were changed to protect the innocent
+        import sys
+        for port in [default_port, 3434, 8798, 23833]:
+            try:
+                self.server_address = host, port
+                TCPServer.server_bind(self)
+                break
+            except socket.error, (err, msg):
+                if err != errno.EADDRINUSE:
+                    raise
+                print >>sys.__stderr__, \
+                    '  WARNING: failed to listen on port %d, trying another' % port
+
+tcpservers = [ForgivingTCPServer, ThreadingTCPServer]
 if hasattr(os, 'fork') and os.name not in ('os2',):
     tcpservers.append(ForkingTCPServer)
 udpservers = [UDPServer, ThreadingUDPServer]
index 2d08f4dde01ba3b272b542fc5dbc3520c0dcbda0..4f89a867ca26566c073ad8fa78a70eb691b88cc5 100644 (file)
@@ -89,6 +89,24 @@ def requires(resource, msg=None):
             msg = "Use of the `%s' resource not enabled" % resource
         raise ResourceDenied(msg)
 
+def bind_port(sock, host='', preferred_port=54321):
+    """Try to bind the sock to a port.  If we are running multiple
+    tests and we don't try multiple ports, the test can fails.  This
+    makes the test more robust."""
+
+    import socket, errno
+    # some random ports that hopefully no one is listening on.
+    for port in [preferred_port, 9907, 10243, 32999]:
+        try:
+            sock.bind((host, port))
+            return port
+        except socket.error, (err, msg):
+            if err != errno.EADDRINUSE:
+                raise
+            print >>sys.__stderr__, \
+                '  WARNING: failed to listen on port %d, trying another' % port
+    raise TestFailed, 'unable to find port to listen on'
+
 FUZZ = 1e-6
 
 def fcmp(x, y): # fuzzy comparison function
index f3c87395100ef8040b57d67c49cbb78e4d467c7a..04240e87b83d1101e31c62b6e49bb5ad8ec70017 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,8 @@ What's New in Python 2.5 beta 1?
 Core and builtins
 -----------------
 
+- Fix the socket tests so they can be run concurrently.
+
 - Removed 5 integers from C frame objects (PyFrameObject).
        f_nlocals, f_ncells, f_nfreevars, f_stack_size, f_restricted.