[Zodb-checkins] CVS: ZEO/ZEO/tests - forker.py:1.5.2.3 testZEO.py:1.9.2.3

Jeremy Hylton jeremy@zope.com
Thu, 23 Aug 2001 20:59:04 -0400


Update of /cvs-repository/ZEO/ZEO/tests
In directory cvs.zope.org:/tmp/cvs-serv25555

Modified Files:
      Tag: zeo-1_0-branch
	forker.py testZEO.py 
Log Message:
Merge changes from trunk (for Windows test success)


=== ZEO/ZEO/tests/forker.py 1.5.2.2 => 1.5.2.3 ===
 import os
 import profile
+import random
 import sys
-import time
 import types
-import ThreadedAsync
 import ZEO.ClientStorage, ZEO.StorageServer
 
 PROFILE = 0
 
-class ZEOServerExit(asyncore.file_dispatcher):
-    """Used to exit ZEO.StorageServer when run is done"""
+if os.name == "nt":
 
-    def writable(self):
-        return 0
+    def start_zeo_server(storage_name, args, port=None):
+        """Start a ZEO server in a separate process.
 
-    def readable(self):
-        return 1
+        Returns the ZEO port, the test server port, and the pid.
+        """
+        import ZEO.tests.winserver
+        if port is None:
+            port = random.randrange(20000, 30000)
+        script = ZEO.tests.winserver.__file__
+        if script.endswith('.pyc'):
+            script = script[:-1]
+        args = (sys.executable, script, str(port), storage_name) + args
+        d = os.environ.copy()
+        d['PYTHONPATH'] = os.pathsep.join(sys.path)
+        pid = os.spawnve(os.P_NOWAIT, sys.executable, args, os.environ)
+        return ('localhost', port), ('localhost', port + 1), pid
+
+else:
+
+    class ZEOServerExit(asyncore.file_dispatcher):
+        """Used to exit ZEO.StorageServer when run is done"""
+
+        def writable(self):
+            return 0
+
+        def readable(self):
+            return 1
+
+        def handle_read(self):
+            buf = self.recv(4)
+            if buf:
+                assert buf == "done"
+                asyncore.socket_map.clear()
 
-    def handle_read(self):
-        buf = self.recv(4)
-        if buf:
-            assert buf == "done"
+        def handle_close(self):
             asyncore.socket_map.clear()
-        
-    def handle_close(self):
-        asyncore.socket_map.clear()
-
-class ZEOClientExit:
-    """Used by client to cause server to exit"""
-    def __init__(self, pipe):
-        self.pipe = pipe
-
-    def close(self):
-        os.write(self.pipe, "done")
-
-def start_zeo_server(storage, addr):
-    rd, wr = os.pipe()
-    pid = os.fork()
-    if pid == 0:
-        if PROFILE:
-            p = profile.Profile()
-            p.runctx("run_server(storage, addr, rd, wr)", globals(),
-                     locals())
-            p.dump_stats("stats.s.%d" % os.getpid())
-        else:
-            run_server(storage, addr, rd, wr)
-        os._exit(0)
-    else:
-        os.close(rd)
-        return pid, ZEOClientExit(wr)
-
-def run_server(storage, addr, rd, wr):
-    # in the child, run the storage server
-    os.close(wr)
-    ZEOServerExit(rd)
-    serv = ZEO.StorageServer.StorageServer(addr, {'1':storage})
-    asyncore.loop()
-    storage.close()
-    if isinstance(addr, types.StringType):
-        os.unlink(addr)
-
-def start_zeo(storage, cache=None, cleanup=None, domain="AF_INET",
-              storage_id="1", cache_size=20000000):
-    """Setup ZEO client-server for storage.
-
-    Returns a ClientStorage instance and a ZEOClientExit instance.
-
-    XXX Don't know if os.pipe() will work on Windows.
-    """
-
-    if domain == "AF_INET":
-        import random
-        addr = '', random.randrange(25000, 30000)
-    elif domain == "AF_UNIX":
-        import tempfile
-        addr = tempfile.mktemp()
-    else:
-        raise ValueError, "bad domain: %s" % domain
-
-    for i in 1, 2, 3:
-        try:
-            pid, exit = start_zeo_server(storage, addr)
-        except socket.error, (num, msg):
-            if num == 98:
-                continue
+
+    class ZEOClientExit:
+        """Used by client to cause server to exit"""
+        def __init__(self, pipe):
+            self.pipe = pipe
+
+        def close(self):
+            os.write(self.pipe, "done")
+
+    def start_zeo_server(storage, addr):
+        rd, wr = os.pipe()
+        pid = os.fork()
+        if pid == 0:
+            if PROFILE:
+                p = profile.Profile()
+                p.runctx("run_server(storage, addr, rd, wr)", globals(),
+                         locals())
+                p.dump_stats("stats.s.%d" % os.getpid())
             else:
-                raise
+                run_server(storage, addr, rd, wr)
+            os._exit(0)
         else:
-            break
-    s = ZEO.ClientStorage.ClientStorage(addr, storage_id,
-                                        debug=1, client=cache,
-                                        cache_size=cache_size,
-                                        min_disconnect_poll=0.5)
-    return s, exit, pid
+            os.close(rd)
+            return pid, ZEOClientExit(wr)
+
+    def run_server(storage, addr, rd, wr):
+        # in the child, run the storage server
+        os.close(wr)
+        ZEOServerExit(rd)
+        serv = ZEO.StorageServer.StorageServer(addr, {'1':storage})
+        asyncore.loop()
+        storage.close()
+        if isinstance(addr, types.StringType):
+            os.unlink(addr)
+
+    def start_zeo(storage, cache=None, cleanup=None, domain="AF_INET",
+                  storage_id="1", cache_size=20000000):
+        """Setup ZEO client-server for storage.
+
+        Returns a ClientStorage instance and a ZEOClientExit instance.
+
+        XXX Don't know if os.pipe() will work on Windows.
+        """
+
+        if domain == "AF_INET":
+            import random
+            addr = '', random.randrange(2000, 3000)
+        elif domain == "AF_UNIX":
+            import tempfile
+            addr = tempfile.mktemp()
+        else:
+            raise ValueError, "bad domain: %s" % domain
+
+        pid, exit = start_zeo_server(storage, addr)
+        s = ZEO.ClientStorage.ClientStorage(addr, storage_id,
+                                            debug=1, client=cache,
+                                            cache_size=cache_size,
+                                            min_disconnect_poll=0.5)
+        return s, exit, pid
 


=== ZEO/ZEO/tests/testZEO.py 1.9.2.2 => 1.9.2.3 ===
 from ZODB.tests.StorageTestBase import zodb_unpickle
 
-
 ZERO = '\0'*8
 
 class DummyDB:
@@ -164,7 +163,57 @@
         # file storage appears to create four files
         for ext in '', '.index', '.lock', '.tmp':
             path = self.__fs_base + ext
-            os.unlink(path)
+            try:
+                os.remove(path)
+            except os.error:
+                pass
+
+class WindowsGenericTests(GenericTests):
+    """Subclass to support server creation on Windows.
+
+    On Windows, the getStorage() design won't work because the storage
+    can't be created in the parent process and passed to the child.
+    All the work has to be done in the server's process.
+    """
+    __super_setUp = StorageTestBase.StorageTestBase.setUp
+    __super_tearDown = StorageTestBase.StorageTestBase.tearDown
+
+    def setUp(self):
+        self.__super_setUp()
+        args = self.getStorageInfo()
+        name = args[0]
+        args = args[1:]
+        zeo_addr, self.test_addr, self.test_pid = \
+                  forker.start_zeo_server(name, args)
+        storage = ZEO.ClientStorage.ClientStorage(zeo_addr, debug=1,
+                                                  min_disconnect_poll=0.5)
+        self._storage = PackWaitWrapper(storage)
+        storage.registerDB(DummyDB(), None)
+
+    def tearDown(self):
+        self._storage.close()
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.connect(self.test_addr)
+        # the connection should cause the storage server to die
+##        os.waitpid(self.test_pid, 0)
+        time.sleep(0.5)
+        self.delStorage()
+        self.__super_tearDown()
+
+class WindowsZEOFileStorageTests(WindowsGenericTests):
+
+    def getStorageInfo(self):
+        self.__fs_base = tempfile.mktemp()
+        return 'FileStorage', self.__fs_base, '1'
+
+    def delStorage(self):
+        # file storage appears to create four files
+        for ext in '', '.index', '.lock', '.tmp':
+            path = self.__fs_base + ext
+            try:
+                os.remove(path)
+            except os.error:
+                pass
 
 class ConnectionTests(ZEOTestBase):
     """Tests that explicitly manage the server process.
@@ -174,47 +223,19 @@
     """
     
     __super_setUp = StorageTestBase.StorageTestBase.setUp
-    __super_tearDown = StorageTestBase.StorageTestBase.tearDown
 
     ports = []
     for i in range(200):
         ports.append(random.randrange(25000, 30000))
     del i
 
-    def setUp(self):
-        """Start a ZEO server using a Unix domain socket
-
-        The ZEO server uses the storage object returned by the
-        getStorage() method.
-        """
-        self.running = 1
-        self.__fs_base = tempfile.mktemp()
-        port = self.ports[0]
-        del self.ports[0]
-        self.addr = '', port
-        pid, exit = self._startServer()
-        self._pid = pid
-        self._server = exit
-        self.__super_setUp()
-
-    def _startServer(self, create=1):
-        fs = FileStorage(self.__fs_base, create=create)
-        return forker.start_zeo_server(fs, self.addr)
-
     def openClientStorage(self, cache='', cache_size=200000, wait=1):
-        base = ZEO.ClientStorage.ClientStorage(self.addr,
-                                               client=cache,
-                                               cache_size=cache_size,
-                                               wait_for_server_on_startup=wait)
-        storage = PackWaitWrapper(base)
-        storage.registerDB(DummyDB(), None)
-        return storage
+        # defined by subclasses
+        pass
 
     def shutdownServer(self):
-        if self.running:
-            self.running = 0
-            self._server.close()
-            os.waitpid(self._pid, 0)
+        # defined by subclasses
+        pass
 
     def tearDown(self):
         """Try to cause the tests to halt"""
@@ -277,15 +298,9 @@
         revid1 = self._dostore(oid, data=obj)
         self.shutdownServer()
         self.running = 1
-        self._pid, self._server = self._startServer(create=0)
+        self._startServer(create=0)
         oid = self._storage.new_oid()
         obj = MinPO(12)
-        # XXX This is a bloody pain.  We're placing a heavy burden on
-        # users to catch a plethora of exceptions in order to write
-        # robust code.  Need to think about implementing John Heintz's
-        # suggestion to make sure all exceptions inherit from
-        # POSException. 
-
         while 1:
             try:
                 revid1 = self._dostore(oid, data=obj)
@@ -294,6 +309,86 @@
                 time.sleep(0.1)
             else:
                 break
+            # XXX This is a bloody pain.  We're placing a heavy burden
+            # on users to catch a plethora of exceptions in order to
+            # write robust code.  Need to think about implementing
+            # John Heintz's suggestion to make sure all exceptions
+            # inherit from POSException. 
+
+class UnixConnectionTests(ConnectionTests):
+    __super_setUp = StorageTestBase.StorageTestBase.setUp
+
+    def setUp(self):
+        """Start a ZEO server using a Unix domain socket
+
+        The ZEO server uses the storage object returned by the
+        getStorage() method.
+        """
+        self.running = 1
+        self.__fs_base = tempfile.mktemp()
+        self.addr = '', self.ports.pop()
+        self._startServer()
+        self.__super_setUp()
+
+    def _startServer(self, create=1):
+        fs = FileStorage(self.__fs_base, create=create)
+        self._pid, self._server = forker.start_zeo_server(fs, self.addr)
+
+    def openClientStorage(self, cache='', cache_size=200000, wait=1):
+        base = ZEO.ClientStorage.ClientStorage(self.addr,
+                                               client=cache,
+                                               cache_size=cache_size,
+                                               wait_for_server_on_startup=wait)
+        storage = PackWaitWrapper(base)
+        storage.registerDB(DummyDB(), None)
+        return storage
+
+    def shutdownServer(self):
+        if self.running:
+            self.running = 0
+            self._server.close()
+            os.waitpid(self._pid, 0)
+
+class WindowsConnectionTests(ConnectionTests):
+    __super_setUp = StorageTestBase.StorageTestBase.setUp
+
+    def setUp(self):
+        self.file = tempfile.mktemp()
+        self._startServer()
+        self.__super_setUp()
+
+    def _startServer(self, create=1):
+        if create == 0:
+            port = self.addr[1]
+        else:
+            port = None
+        self.addr, self.test_a, pid = forker.start_zeo_server('FileStorage',
+                                                              (self.file,
+                                                               str(create)),
+                                                              port)
+        self.running = 1
+
+    def openClientStorage(self, cache='', cache_size=200000, wait=1):
+        base = ZEO.ClientStorage.ClientStorage(self.addr,
+                                               client=cache,
+                                               cache_size=cache_size,
+                                               debug=1,
+                                               wait_for_server_on_startup=wait)
+        storage = PackWaitWrapper(base)
+        storage.registerDB(DummyDB(), None)
+        return storage
+
+    def shutdownServer(self):
+        if self.running:
+            self.running = 0
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.connect(self.test_a)
+            s.close()
+            time.sleep(1.0)
+
+    def tearDown(self):
+        self.shutdownServer()
+
 
 def get_methods(klass):
     l = [klass]
@@ -307,11 +402,18 @@
                 meth[k] = 1
     return meth.keys()
 
+if os.name == "posix":
+    test_classes = ZEOFileStorageTests, UnixConnectionTests
+elif os.name == "nt":
+    test_classes = WindowsZEOFileStorageTests, WindowsConnectionTests
+else:
+    raise RuntimeError, "unsupported os: %s" % os.name
+
 def makeTestSuite(testname=''):
     suite = unittest.TestSuite()
     name = 'check' + testname
     lname = len(name)
-    for klass in ZEOFileStorageTests, ConnectionTests:
+    for klass in test_classes:
         for meth in get_methods(klass):
             if meth[:lname] == name:
                 suite.addTest(klass(meth))