[Zope-Checkins] CVS: ZODB3/ZODB/tests - MTStorage.py:1.6.4.1

Jeremy Hylton jeremy@zope.com
Tue, 13 May 2003 13:59:09 -0400


Update of /cvs-repository/ZODB3/ZODB/tests
In directory cvs.zope.org:/tmp/cvs-serv19734/tests

Modified Files:
      Tag: ZODB3-3_1-branch
	MTStorage.py 
Log Message:
Fix occasional assertion errors in 7 zodb client threads test.

Backport code from ZODB4 that causes the test to fail when an
exception occurs in a thread.

Add a sync() call after abort() to clear ReadConflictError.  This is
necessary in ZODB 3.1 because the Connection does not register with
the TM.


=== ZODB3/ZODB/tests/MTStorage.py 1.6 => 1.6.4.1 ===
--- ZODB3/ZODB/tests/MTStorage.py:1.6	Thu Sep 19 16:42:00 2002
+++ ZODB3/ZODB/tests/MTStorage.py	Tue May 13 13:59:08 2003
@@ -1,4 +1,5 @@
 import random
+import sys
 import threading
 import time
 
@@ -18,19 +19,50 @@
     l.sort()
     return l
 
-class ZODBClientThread(threading.Thread):
+class TestThread(threading.Thread):
+    """Base class for defining threads that run from unittest.
 
-    __super_init = threading.Thread.__init__
+    If the thread exits with an uncaught exception, catch it and
+    re-raise it when the thread is joined.  The re-raise will cause
+    the test to fail.
+
+    The subclass should define a runtest() method instead of a run()
+    method.
+    """
+
+    def __init__(self, test):
+        threading.Thread.__init__(self)
+        self.test = test
+        self._fail = None
+        self._exc_info = None
+
+    def run(self):
+        try:
+            self.runtest()
+        except:
+            self._exc_info = sys.exc_info()
+
+    def fail(self, msg=""):
+        self._test.fail(msg)
+
+    def join(self, timeout=None):
+        threading.Thread.join(self, timeout)
+        if self._exc_info:
+            raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
+
+class ZODBClientThread(TestThread):
+
+    __super_init = TestThread.__init__
 
     def __init__(self, db, test, commits=10, delay=SHORT_DELAY):
-        self.__super_init()
+        self.__super_init(test)
         self.setDaemon(1)
         self.db = db
         self.test = test
         self.commits = commits
         self.delay = delay
 
-    def run(self):
+    def runtest(self):
         conn = self.db.open()
         root = conn.root()
         d = self.get_thread_dict(root)
@@ -56,27 +88,28 @@
                 root[name] = m
                 get_transaction().commit()
                 break
-            except ConflictError:
+            except ConflictError, err:
                 get_transaction().abort()
+                root._p_jar.sync()
         for i in range(10):
             try:
                 return root.get(name)
             except ConflictError:
                 get_transaction().abort()
 
-class StorageClientThread(threading.Thread):
+class StorageClientThread(TestThread):
 
-    __super_init = threading.Thread.__init__
+    __super_init = TestThread.__init__
 
     def __init__(self, storage, test, commits=10, delay=SHORT_DELAY):
-        self.__super_init()
+        self.__super_init(test)
         self.storage = storage
         self.test = test
         self.commits = commits
         self.delay = delay
         self.oids = {}
 
-    def run(self):
+    def runtest(self):
         for i in range(self.commits):
             self.dostore(i)
         self.check()
@@ -120,7 +153,7 @@
 
 class ExtStorageClientThread(StorageClientThread):
 
-    def run(self):
+    def runtest(self):
         # pick some other storage ops to execute
         ops = [getattr(self, meth) for meth in dir(ExtStorageClientThread)
                if meth.startswith('do_')]