[Zodb-checkins] SVN: ZODB/trunk/src/ZEO/tests/ Improved the get_port function to address a race condition. This

Jim Fulton jim at zope.com
Sat Nov 15 14:56:17 EST 2008


Log message for revision 92986:
  Improved the get_port function to address a race condition. This
  requires passing a test object.
  
  With this, it appears that I can run tests in parallel without getting
  extra spurious errors.
  

Changed:
  U   ZODB/trunk/src/ZEO/tests/ConnectionTests.py
  U   ZODB/trunk/src/ZEO/tests/forker.py
  U   ZODB/trunk/src/ZEO/tests/testZEO.py
  U   ZODB/trunk/src/ZEO/tests/zeoserver.py

-=-
Modified: ZODB/trunk/src/ZEO/tests/ConnectionTests.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/ConnectionTests.py	2008-11-15 19:09:08 UTC (rev 92985)
+++ ZODB/trunk/src/ZEO/tests/ConnectionTests.py	2008-11-15 19:56:16 UTC (rev 92986)
@@ -165,7 +165,7 @@
         self.addr.append(self._getAddr())
 
     def _getAddr(self):
-        return 'localhost', forker.get_port()
+        return 'localhost', forker.get_port(self)
 
     def getConfig(self, path, create, read_only):
         raise NotImplementedError

Modified: ZODB/trunk/src/ZEO/tests/forker.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/forker.py	2008-11-15 19:09:08 UTC (rev 92985)
+++ ZODB/trunk/src/ZEO/tests/forker.py	2008-11-15 19:56:16 UTC (rev 92986)
@@ -23,6 +23,7 @@
 import StringIO
 import tempfile
 import logging
+import zope.testing.setupstack
 
 logger = logging.getLogger('ZEO.tests.forker')
 
@@ -203,7 +204,7 @@
         logger.debug('shutdown_zeo_server(): acked: %s' % ack)
         s.close()
 
-def get_port():
+def get_port(test=None):
     """Return a port that is not in use.
 
     Checks if a port is in use by trying to connect to it.  Assumes it
@@ -213,6 +214,10 @@
 
     Raises RuntimeError after 10 tries.
     """
+
+    if test is not None:
+        return get_port2(test)
+    
     for i in range(10):
         port = random.randrange(20000, 30000)
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -238,3 +243,37 @@
             s.close()
             s1.close()
     raise RuntimeError("Can't find port")
+
+def get_port2(test):
+    for i in range(10):
+        while 1:
+            port = random.randrange(20000, 30000)
+            if port%3 == 0:
+                break
+
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            s.bind(('localhost', port+2))
+        except socket.error, e:
+            if e[0] != errno.EADDRINUSE:
+                raise
+            continue
+
+        if not (can_connect(port) or can_connect(port+1)):
+            zope.testing.setupstack.register(test, s.close)
+            return port
+
+        s.close()
+
+    raise RuntimeError("Can't find port")
+
+def can_connect(port):
+    c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    try:
+        c.connect(('localhost', port))
+    except socket.error:
+        return False  # Perhaps we should check value of error too.
+    else:
+        c.close()
+        return True
+    

Modified: ZODB/trunk/src/ZEO/tests/testZEO.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/testZEO.py	2008-11-15 19:09:08 UTC (rev 92985)
+++ ZODB/trunk/src/ZEO/tests/testZEO.py	2008-11-15 19:56:16 UTC (rev 92986)
@@ -224,7 +224,7 @@
     def setUp(self):
         StorageTestBase.StorageTestBase.setUp(self)
         logger.info("setUp() %s", self.id())
-        port = get_port()
+        port = get_port(self)
         zconf = forker.ZEOConfig(('', port))
         zport, adminaddr, pid, path = forker.start_zeo_server(self.getConfig(),
                                                               zconf, port)
@@ -310,7 +310,7 @@
         """ % tempfile.mktemp(dir='.')
 
     def _new_storage(self):
-        port = get_port()
+        port = get_port(self)
         zconf = forker.ZEOConfig(('', port))
         zport, adminaddr, pid, path = forker.start_zeo_server(self.getConfig(),
                                                               zconf, port)
@@ -571,7 +571,7 @@
 
     def _makeBaseStorage(self):
         logger.info("setUp() %s", self.id())
-        port = get_port()
+        port = get_port(self)
         zconf = forker.ZEOConfig(('', port))
         zport, adminaddr, pid, path = forker.start_zeo_server(self.getConfig(),
                                                               zconf, port)
@@ -1091,28 +1091,40 @@
     connection closed
     """
 
-test_classes = [FileStorageTests, FileStorageRecoveryTests,
-                MappingStorageTests, DemoStorageTests,
-                BlobAdaptedFileStorageTests, BlobWritableCacheTests,
-                ConfigurationTests,
-                ]
+slow_test_classes = [
+    BlobAdaptedFileStorageTests, BlobWritableCacheTests,
+    DemoStorageTests, FileStorageTests, MappingStorageTests,
+    ]
+    
+quick_test_classes = [FileStorageRecoveryTests, ConfigurationTests]
 
+def setUp(test):
+    ZODB.tests.util.setUp(test)
+    test.globs['get_port'] = lambda : get_port(test)
+
 def test_suite():
     suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(ZODB.tests.util.AAAA_Test_Runner_Hack))
-    suite.addTest(doctest.DocTestSuite(
-        setUp=zope.testing.setupstack.setUpDirectory,
-        tearDown=zope.testing.setupstack.tearDown))
-    suite.addTest(doctest.DocFileSuite(
-        'registerDB.test'
-        ))
-    suite.addTest(
-        doctest.DocFileSuite('zeo-fan-out.test',
-                             setUp=zope.testing.setupstack.setUpDirectory,
-                             tearDown=zope.testing.setupstack.tearDown,
-                             ),
+
+    # Collect misc tests into their own layer to educe size of
+    # unit test layer
+    zeo = unittest.TestSuite()
+    zeo.addTest(unittest.makeSuite(ZODB.tests.util.AAAA_Test_Runner_Hack))
+    zeo.addTest(doctest.DocTestSuite(
+        setUp=setUp, tearDown=zope.testing.setupstack.tearDown))
+    zeo.addTest(doctest.DocFileSuite('registerDB.test'))
+    zeo.addTest(
+        doctest.DocFileSuite(
+            'zeo-fan-out.test',
+            setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
+            ),
         )
-    for klass in test_classes:
+    for klass in quick_test_classes:
+        zeo.addTest(unittest.makeSuite(klass, "check"))
+    zeo.layer = ZODB.tests.util.MininalTestLayer('testZeo-misc')
+    suite.addTest(zeo)
+
+    # Put the heavyweights in their own layers
+    for klass in slow_test_classes:
         sub = unittest.makeSuite(klass, "check")
         sub.layer = ZODB.tests.util.MininalTestLayer(klass.__name__)
         suite.addTest(sub)

Modified: ZODB/trunk/src/ZEO/tests/zeoserver.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/zeoserver.py	2008-11-15 19:09:08 UTC (rev 92985)
+++ ZODB/trunk/src/ZEO/tests/zeoserver.py	2008-11-15 19:56:16 UTC (rev 92986)
@@ -195,7 +195,8 @@
         log(label, 'creating the test server, keep: %s', keep)
         t = ZEOTestServer(test_addr, server, keep)
     except socket.error, e:
-        if e[0] <> errno.EADDRINUSE: raise
+        if e[0] != errno.EADDRINUSE:
+            raise
         log(label, 'addr in use, closing and exiting')
         storage.close()
         cleanup(storage)



More information about the Zodb-checkins mailing list