[Zodb-checkins] CVS: Zope/lib/python/ZODB/tests - BasicStorage.py:1.14.26.1 ConflictResolution.py:1.6.50.1 Corruption.py:1.2.56.1 HistoryStorage.py:1.5.44.1 IteratorStorage.py:1.4.44.1 StorageTestBase.py:1.9.26.1 Synchronization.py:1.2.56.1 TransactionalUndoStorage.py:1.13.44.1 TransactionalUndoVersionStorage.py:1.4.88.1 VersionStorage.py:1.11.30.1 testDemoStorage.py:1.2.34.1 testFileStorage.py:1.13.32.1 testMappingStorage.py:1.1.34.1

Fred L. Drake, Jr. fdrake@acm.org
Wed, 20 Feb 2002 10:05:07 -0500


Update of /cvs-repository/Zope/lib/python/ZODB/tests
In directory cvs.zope.org:/tmp/cvs-serv1061/tests

Modified Files:
      Tag: Zope-2_5-branch
	BasicStorage.py ConflictResolution.py Corruption.py 
	HistoryStorage.py IteratorStorage.py StorageTestBase.py 
	Synchronization.py TransactionalUndoStorage.py 
	TransactionalUndoVersionStorage.py VersionStorage.py 
	testDemoStorage.py testFileStorage.py testMappingStorage.py 
Log Message:
Merge ZODB from trunk.

=== Zope/lib/python/ZODB/tests/BasicStorage.py 1.14 => 1.14.26.1 ===
 
 from ZODB.tests.MinPO import MinPO
-from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
+from ZODB.tests.StorageTestBase \
+     import zodb_unpickle, zodb_pickle, handle_serials
 
 ZERO = '\0'*8
 
@@ -18,14 +19,15 @@
 
 class BasicStorage:
     def checkBasics(self):
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         # This should simply return
-        self._storage.tpc_begin(self._transaction)
+        self._storage.tpc_begin(t)
         # Aborting is easy
-        self._storage.tpc_abort(self._transaction)
+        self._storage.tpc_abort(t)
         # Test a few expected exceptions when we're doing operations giving a
         # different Transaction object than the one we've begun on.
-        self._storage.tpc_begin(self._transaction)
+        self._storage.tpc_begin(t)
         self.assertRaises(
             POSException.StorageTransactionError,
             self._storage.store,
@@ -64,12 +66,12 @@
             POSException.StorageTransactionError,
             self._storage.store,
             0, 1, 2, 3, Transaction())
-        self._storage.tpc_abort(self._transaction)
+        self._storage.tpc_abort(t)
 
     def checkSerialIsNoneForInitialRevision(self):
         eq = self.assertEqual
         oid = self._storage.new_oid()
-        txn = self._transaction
+        txn = Transaction()
         self._storage.tpc_begin(txn)
         # Use None for serial.  Don't use _dostore() here because that coerces
         # serial=None to serial=ZERO.
@@ -77,7 +79,7 @@
                                        '', txn)
         r2 = self._storage.tpc_vote(txn)
         self._storage.tpc_finish(txn)
-        newrevid = self._handle_serials(oid, r1, r2)
+        newrevid = handle_serials(oid, r1, r2)
         data, revid = self._storage.load(oid, '')
         value = zodb_unpickle(data)
         eq(value, MinPO(11))
@@ -118,13 +120,12 @@
 
     def checkWriteAfterAbort(self):
         oid = self._storage.new_oid()
-        self._storage.tpc_begin(self._transaction)
-        self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)),
-                            '', self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
         # Now abort this transaction
-        self._storage.tpc_abort(self._transaction)
+        self._storage.tpc_abort(t)
         # Now start all over again
-        self._transaction = Transaction()
         oid = self._storage.new_oid()
         self._dostore(oid=oid, data=MinPO(6))
 
@@ -132,14 +133,13 @@
         oid1 = self._storage.new_oid()
         revid1 = self._dostore(oid=oid1, data=MinPO(-2))
         oid = self._storage.new_oid()
-        self._storage.tpc_begin(self._transaction)
-        self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)),
-                            '', self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
         # Now abort this transaction
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_abort(self._transaction)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_abort(t)
         # Now start all over again
-        self._transaction = Transaction()
         oid = self._storage.new_oid()
         revid = self._dostore(oid=oid, data=MinPO(6))
 
@@ -173,3 +173,14 @@
         # And another one
         revid2 = self._dostore(oid, revid=revid1, data=p42)
         eq(revid2, self._storage.getSerial(oid))
+
+    def checkTwoArgBegin(self):
+        # XXX how standard is three-argument tpc_begin()?
+        t = Transaction()
+        tid = chr(42) * 8
+        self._storage.tpc_begin(t, tid)
+        oid = self._storage.new_oid()
+        data = zodb_pickle(MinPO(8))
+        self._storage.store(oid, None, data, '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)


=== Zope/lib/python/ZODB/tests/ConflictResolution.py 1.6 => 1.6.50.1 ===
         info = self._storage.undoInfo()
         tid = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
-        self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_finish(t)
 
     def checkUndoUnresolvable(self):
         # This test is based on checkNotUndoable in the
@@ -164,9 +165,9 @@
         # Start the undo
         info = self._storage.undoInfo()
         tid = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
-        self.assertRaises(UndoError,
-                          self._storage.transactionalUndo,
-                          tid, self._transaction)
-        self._storage.tpc_abort(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self.assertRaises(UndoError, self._storage.transactionalUndo,
+                          tid, t)
+        self._storage.tpc_abort(t)
 


=== Zope/lib/python/ZODB/tests/Corruption.py 1.2 => 1.2.56.1 ===
 
 class FileStorageCorruptTests(StorageTestBase):
-    __super_setUp = StorageTestBase.setUp
-    __super_tearDown = StorageTestBase.tearDown
 
     def setUp(self):
         self.path = tempfile.mktemp()
         self._storage = ZODB.FileStorage.FileStorage(self.path, create=1)
-        self.__super_setUp()
 
     def tearDown(self):
-        self.__super_tearDown()
+        self._storage.close()
         for ext in '', '.old', '.tmp', '.lock', '.index':
             path = self.path + ext
             if os.path.exists(path):


=== Zope/lib/python/ZODB/tests/HistoryStorage.py 1.5 => 1.5.44.1 ===
 """
 
+from ZODB.Transaction import Transaction
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_unpickle
 
@@ -111,10 +112,11 @@
         revid6 = self._dostore(oid, revid=revid5, data=MinPO(16),
                                version=version)
         # Now commit the version
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.commitVersion(version, '', self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.commitVersion(version, '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         # After consultation with Jim, we agreed that the semantics of
         # revision id's after a version commit is that the committed object
         # gets a new serial number (a.k.a. revision id).  Note that
@@ -168,10 +170,11 @@
         revid6 = self._dostore(oid, revid=revid5, data=MinPO(16),
                                version=version)
         # Now commit the version
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.abortVersion(version, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion(version, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         # After consultation with Jim, we agreed that the semantics of
         # revision id's after a version commit is that the committed object
         # gets a new serial number (a.k.a. revision id).  Note that


=== Zope/lib/python/ZODB/tests/IteratorStorage.py 1.4 => 1.4.44.1 ===
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_unpickle
-
+from ZODB.utils import U64, p64
+from ZODB.Transaction import Transaction
 
 
-class IteratorStorage:
-    def checkSimpleIteration(self):
+class IteratorCompare:
+
+    def iter_verify(self, txniter, revids, val0):
         eq = self.assertEqual
-        # Store a bunch of revisions of a single object
-        oid = self._storage.new_oid()
-        revid1 = self._dostore(oid, data=MinPO(11))
-        revid2 = self._dostore(oid, revid=revid1, data=MinPO(12))
-        revid3 = self._dostore(oid, revid=revid2, data=MinPO(13))
-        # Now iterate over all the transactions
-        val = 11
-        txniter = self._storage.iterator()
-        for reciter, revid in zip(txniter, (revid1, revid2, revid3)):
+        oid = self._oid
+        val = val0
+        for reciter, revid in zip(txniter, revids + [None]):
             eq(reciter.tid, revid)
             for rec in reciter:
                 eq(rec.oid, oid)
@@ -28,3 +24,147 @@
                 eq(rec.version, '')
                 eq(zodb_unpickle(rec.data), MinPO(val))
                 val = val + 1
+        eq(val, val0 + len(revids))
+
+class IteratorStorage(IteratorCompare):
+
+    def checkSimpleIteration(self):
+        # Store a bunch of revisions of a single object
+        self._oid = oid = self._storage.new_oid()
+        revid1 = self._dostore(oid, data=MinPO(11))
+        revid2 = self._dostore(oid, revid=revid1, data=MinPO(12))
+        revid3 = self._dostore(oid, revid=revid2, data=MinPO(13))
+        # Now iterate over all the transactions and compare carefully
+        txniter = self._storage.iterator()
+        self.iter_verify(txniter, [revid1, revid2, revid3], 11)
+
+    def checkClose(self):
+        self._oid = oid = self._storage.new_oid()
+        revid1 = self._dostore(oid, data=MinPO(11))
+        txniter = self._storage.iterator()
+        txniter.close()
+        self.assertRaises(IOError, txniter.__getitem__, 0)
+
+    def checkVersionIterator(self):
+        if not self._storage.supportsVersions():
+            return
+        self._dostore()
+        self._dostore(version='abort')
+        self._dostore()
+        self._dostore(version='abort')
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.abortVersion('abort', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
+
+        self._dostore(version='commit')
+        self._dostore()
+        self._dostore(version='commit')
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.commitVersion('commit', '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
+
+        txniter = self._storage.iterator()
+        for trans in txniter:
+            for data in trans:
+                pass
+
+    def checkUndoZombieNonVersion(self):
+        if not hasattr(self._storage, 'supportsTransactionalUndo'):
+            return
+        if not self._storage.supportsTransactionalUndo():
+            return
+
+        oid = self._storage.new_oid()
+        revid = self._dostore(oid, data=MinPO(94))
+        # Get the undo information
+        info = self._storage.undoInfo()
+        tid = info[0]['id']
+        # Undo the creation of the object, rendering it a zombie
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
+        # Now attempt to iterator over the storage
+        iter = self._storage.iterator()
+        for txn in iter:
+            for rec in txn:
+                pass
+
+        # The last transaction performed an undo of the transaction that
+        # created object oid.  (As Barry points out, the object is now in the
+        # George Bailey state.)  Assert that the final data record contains
+        # None in the data attribute.
+        self.assertEqual(rec.oid, oid)
+        self.assertEqual(rec.data, None)
+
+
+class ExtendedIteratorStorage(IteratorCompare):
+
+    def checkExtendedIteration(self):
+        # Store a bunch of revisions of a single object
+        self._oid = oid = self._storage.new_oid()
+        revid1 = self._dostore(oid, data=MinPO(11))
+        revid2 = self._dostore(oid, revid=revid1, data=MinPO(12))
+        revid3 = self._dostore(oid, revid=revid2, data=MinPO(13))
+        revid4 = self._dostore(oid, revid=revid3, data=MinPO(14))
+        # Note that the end points are included
+        # Iterate over all of the transactions with explicit start/stop
+        txniter = self._storage.iterator(revid1, revid4)
+        self.iter_verify(txniter, [revid1, revid2, revid3, revid4], 11)
+        # Iterate over some of the transactions with explicit start
+        txniter = self._storage.iterator(revid3)
+        self.iter_verify(txniter, [revid3, revid4], 13)
+        # Iterate over some of the transactions with explicit stop
+        txniter = self._storage.iterator(None, revid2)
+        self.iter_verify(txniter, [revid1, revid2], 11)
+        # Iterate over some of the transactions with explicit start+stop
+        txniter = self._storage.iterator(revid2, revid3)
+        self.iter_verify(txniter, [revid2, revid3], 12)
+        # Specify an upper bound somewhere in between values
+        revid3a = p64((U64(revid3) + U64(revid4)) / 2)
+        txniter = self._storage.iterator(revid2, revid3a)
+        self.iter_verify(txniter, [revid2, revid3], 12)
+        # Specify a lower bound somewhere in between values.
+        # revid2 == revid1+1 is very likely on Windows.  Adding 1 before
+        # dividing ensures that "the midpoint" we compute is strictly larger
+        # than revid1.
+        revid1a = p64((U64(revid1) + 1 + U64(revid2)) / 2)
+        assert revid1 < revid1a
+        txniter = self._storage.iterator(revid1a, revid3a)
+        self.iter_verify(txniter, [revid2, revid3], 12)
+        # Specify an empty range
+        txniter = self._storage.iterator(revid3, revid2)
+        self.iter_verify(txniter, [], 13)
+        # Specify a singleton range
+        txniter = self._storage.iterator(revid3, revid3)
+        self.iter_verify(txniter, [revid3], 13)
+
+class IteratorDeepCompare:
+    def compare(self, storage1, storage2):
+        eq = self.assertEqual
+        iter1 = storage1.iterator()
+        iter2 = storage2.iterator()
+        for txn1, txn2 in zip(iter1, iter2):
+            eq(txn1.tid,         txn2.tid)
+            eq(txn1.status,      txn2.status)
+            eq(txn1.user,        txn2.user)
+            eq(txn1.description, txn2.description)
+            eq(txn1._extension,  txn2._extension)
+            for rec1, rec2 in zip(txn1, txn2):
+                eq(rec1.oid,     rec2.oid)
+                eq(rec1.serial,  rec2.serial)
+                eq(rec1.version, rec2.version)
+                eq(rec1.data,    rec2.data)
+            # Make sure there are no more records left in rec1 and rec2,
+            # meaning they were the same length.
+            self.assertRaises(IndexError, txn1.next)
+            self.assertRaises(IndexError, txn2.next)
+        # Make sure ther are no more records left in txn1 and txn2, meaning
+        # they were the same length
+        self.assertRaises(IndexError, iter1.next)
+        self.assertRaises(IndexError, iter2.next)


=== Zope/lib/python/ZODB/tests/StorageTestBase.py 1.9 => 1.9.26.1 ===
     return inst
 
+def handle_all_serials(oid, *args):
+    """Return dict of oid to serialno from store() and tpc_vote().
+
+    Raises an exception if one of the calls raised an exception.
+
+    The storage interface got complicated when ZEO was introduced.
+    Any individual store() call can return None or a sequence of
+    2-tuples where the 2-tuple is either oid, serialno or an
+    exception to be raised by the client.
+
+    The original interface just returned the serialno for the
+    object.
+    """
+    d = {}
+    for arg in args:
+        if isinstance(arg, types.StringType):
+            d[oid] = arg
+        elif arg is None:
+            pass
+        else:
+            for oid, serial in arg:
+                if not isinstance(serial, types.StringType):
+                    raise serial # error from ZEO server
+                d[oid] = serial
+    return d
+
+def handle_serials(oid, *args):
+    """Return the serialno for oid based on multiple return values.
+
+    A helper for function _handle_all_serials().
+    """
+    args = (oid,) + args
+    return apply(handle_all_serials, args)[oid]
+
 def import_helper(name):
     mod = __import__(name)
-    for part in string.split(name, ".")[1:]:
-        mod = getattr(mod, part)
-    return mod
+    return sys.modules[name]
 
 
 class StorageTestBase(unittest.TestCase):
+
+    # XXX It would be simpler if concrete tests didn't need to extend
+    # setUp() and tearDown().
+    
     def setUp(self):
         # You need to override this with a setUp that creates self._storage
-        self._transaction = Transaction()
+        self._storage = None
 
     def _close(self):
         # You should override this if closing your storage requires additional
         # shutdown operations.
-        self._transaction.abort()
-        self._storage.close()
+        if self._storage is not None:
+            self._storage.close()
 
     def tearDown(self):
         self._close()
 
-    def _handle_all_serials(self, oid, *args):
-        """Return dict of oid to serialno from store() and tpc_vote().
-
-        Raises an exception if one of the calls raised an exception.
-
-        The storage interface got complicated when ZEO was introduced.
-        Any individual store() call can return None or a sequence of
-        2-tuples where the 2-tuple is either oid, serialno or an
-        exception to be raised by the client.
-
-        The original interface just returned the serialno for the
-        object.
-        """
-        d = {}
-        for arg in args:
-            if isinstance(arg, types.StringType):
-                d[oid] = arg
-            elif arg is None:
-                pass
-            else:
-                for oid, serial in arg:
-                    if not isinstance(serial, types.StringType):
-                        raise arg
-                    d[oid] = serial
-        return d
-
-    def _handle_serials(self, oid, *args):
-        """Return the serialno for oid based on multiple return values.
-
-        A helper for function _handle_all_serials().
-        """
-        args = (oid,) + args
-        return apply(self._handle_all_serials, args)[oid]
-
     def _dostore(self, oid=None, revid=None, data=None, version=None,
-                 already_pickled=0):
+                 already_pickled=0, user=None, description=None):
         """Do a complete storage transaction.  The defaults are:
         
          - oid=None, ask the storage for a new oid
@@ -146,14 +148,24 @@
         if version is None:
             version = ''
         # Begin the transaction
-        self._storage.tpc_begin(self._transaction)
-        # Store an object
-        r1 = self._storage.store(oid, revid, data, version,
-                                       self._transaction)
-        # Finish the transaction
-        r2 = self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
-        return self._handle_serials(oid, r1, r2)
+        t = Transaction()
+        if user is not None:
+            t.user = user
+        if description is not None:
+            t.description = description
+        try:
+            self._storage.tpc_begin(t)
+            # Store an object
+            r1 = self._storage.store(oid, revid, data, version, t)
+            # Finish the transaction
+            r2 = self._storage.tpc_vote(t)
+            revid = handle_serials(oid, r1, r2)
+            self._storage.tpc_finish(t)
+        except:
+            self._storage.tpc_abort(t)
+            raise
+        return revid
         
-    def _dostoreNP(self, oid=None, revid=None, data=None, version=None):
+    def _dostoreNP(self, oid=None, revid=None, data=None, version=None,
+                   user=None, description=None):
         return self._dostore(oid, revid, data, version, already_pickled=1)


=== Zope/lib/python/ZODB/tests/Synchronization.py 1.2 => 1.2.56.1 ===
 
     def verifyWrongTrans(self, callable, *args):
-        self._storage.tpc_begin(self._transaction)
-        args = (StorageTransactionError, callable) + args
-        apply(self.assertRaises, args)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self.assertRaises(StorageTransactionError, callable, *args)
+        self._storage.tpc_abort(t)
 
     def checkAbortVersionNotCommitting(self):
         self.verifyNotCommitting(self._storage.abortVersion,
-                                 VERSION, self._transaction)
+                                 VERSION, Transaction())
 
     def checkAbortVersionWrongTrans(self):
         self.verifyWrongTrans(self._storage.abortVersion,
@@ -81,7 +82,7 @@
 
     def checkCommitVersionNotCommitting(self):
         self.verifyNotCommitting(self._storage.commitVersion,
-                                 VERSION, "", self._transaction)
+                                 VERSION, "", Transaction())
 
     def checkCommitVersionWrongTrans(self):
         self.verifyWrongTrans(self._storage.commitVersion,
@@ -90,7 +91,7 @@
 
     def checkStoreNotCommitting(self):
         self.verifyNotCommitting(self._storage.store,
-                                 OID, SERIALNO, "", "", self._transaction)
+                                 OID, SERIALNO, "", "", Transaction())
     
     def checkStoreWrongTrans(self):
         self.verifyWrongTrans(self._storage.store,
@@ -107,18 +108,26 @@
         self._storage.tpc_abort(Transaction())
 
     def checkAbortWrongTrans(self):
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._storage.tpc_abort(Transaction())
+        self._storage.tpc_abort(t)
 
     def checkFinishNotCommitting(self):
-        self._storage.tpc_finish(Transaction())
+        t = Transaction()
+        self._storage.tpc_finish(t)
+        self._storage.tpc_abort(t)
 
     def checkFinishWrongTrans(self):
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._storage.tpc_finish(Transaction())
+        self._storage.tpc_abort(t)
     
     def checkBeginCommitting(self):
-        self._storage.tpc_begin(self._transaction)
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.tpc_begin(t)
+        self._storage.tpc_abort(t)
 
     # XXX how to check undo?


=== Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py 1.13 => 1.13.44.1 ===
 import types
 from ZODB import POSException
+from ZODB.Transaction import Transaction
 
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
@@ -37,13 +38,14 @@
 
     def _multi_obj_transaction(self, objs):
         newrevs = {}
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
         for oid, rev, data in objs:
-            self._transaction_store(oid, rev, data, '', self._transaction)
+            self._transaction_store(oid, rev, data, '', t)
             newrevs[oid] = None
-        self._transaction_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        self._transaction_vote(t)
+        self._storage.tpc_finish(t)
         for oid in newrevs.keys():
             newrevs[oid] = self._transaction_newserial(oid)
         return newrevs
@@ -58,11 +60,12 @@
         info = self._storage.undoInfo()
         tid = info[0]['id']
         # Now start an undo transaction
-        self._transaction.note('undo1')
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        t.note('undo1')
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -70,11 +73,12 @@
         # Do another one
         info = self._storage.undoInfo()
         tid = info[2]['id']
-        self._transaction.note('undo2')
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        t.note('undo2')
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -82,11 +86,12 @@
         # Try to undo the first record
         info = self._storage.undoInfo()
         tid = info[4]['id']
-        self._transaction.note('undo3')
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        t.note('undo3')
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
 
         eq(len(oids), 1)
         eq(oids[0], oid)
@@ -96,10 +101,11 @@
         # And now let's try to redo the object's creation
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -113,10 +119,11 @@
         # Undo the last transaction
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -125,10 +132,11 @@
         # creation.  Let's undo the object creation.
         info = self._storage.undoInfo()
         tid = info[2]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         self.assertRaises(KeyError, self._storage.load, oid, '')
@@ -141,10 +149,11 @@
         # Undo the last transaction
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -153,10 +162,11 @@
         # creation.  Let's redo the last undo
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -171,26 +181,28 @@
         oid2 = self._storage.new_oid()
         revid1 = revid2 = ZERO
         # Store two objects in the same transaction
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
-        self._transaction_store(oid1, revid1, p31, '', self._transaction)
-        self._transaction_store(oid2, revid2, p51, '', self._transaction)
+        self._transaction_store(oid1, revid1, p31, '', t)
+        self._transaction_store(oid2, revid2, p51, '', t)
         # Finish the transaction
-        self._transaction_vote(self._transaction)
+        self._transaction_vote(t)
         revid1 = self._transaction_newserial(oid1)
         revid2 = self._transaction_newserial(oid2)
-        self._storage.tpc_finish(self._transaction)
+        self._storage.tpc_finish(t)
         eq(revid1, revid2)
         # Update those same two objects
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
-        self._transaction_store(oid1, revid1, p32, '', self._transaction)
-        self._transaction_store(oid2, revid2, p52, '', self._transaction)
+        self._transaction_store(oid1, revid1, p32, '', t)
+        self._transaction_store(oid2, revid2, p52, '', t)
         # Finish the transaction
-        self._transaction_vote(self._transaction)
+        self._transaction_vote(t)
         revid1 = self._transaction_newserial(oid1)
         revid2 = self._transaction_newserial(oid2)
-        self._storage.tpc_finish(self._transaction)
+        self._storage.tpc_finish(t)
         eq(revid1, revid2)
         # Make sure the objects have the current value
         data, revid1 = self._storage.load(oid1, '')
@@ -200,10 +212,11 @@
         # Now attempt to undo the transaction containing two objects
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 2)
         self.failUnless(oid1 in oids)
         self.failUnless(oid2 in oids)
@@ -249,14 +262,15 @@
         info = self._storage.undoInfo()
         tid = info[0]['id']
         tid1 = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        oids1 = self._storage.transactionalUndo(tid1, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        oids1 = self._storage.transactionalUndo(tid1, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         # We get the finalization stuff called an extra time:
-##        self._storage.tpc_vote(self._transaction)
-##        self._storage.tpc_finish(self._transaction)
+##        self._storage.tpc_vote(t)
+##        self._storage.tpc_finish(t)
         eq(len(oids), 2)
         eq(len(oids1), 2)
         unless(oid1 in oids)
@@ -268,10 +282,11 @@
         # Now try to undo the one we just did to undo, whew
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 2)
         unless(oid1 in oids)
         unless(oid2 in oids)
@@ -292,23 +307,25 @@
         revid1 = self._dostore(oid1, data=p31, already_pickled=1)
         revid2 = self._dostore(oid2, data=p51, already_pickled=1)
         # Update those same two objects
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
-        self._transaction_store(oid1, revid1, p32, '', self._transaction)
-        self._transaction_store(oid2, revid2, p52, '', self._transaction)
+        self._transaction_store(oid1, revid1, p32, '', t)
+        self._transaction_store(oid2, revid2, p52, '', t)
         # Finish the transaction
-        self._transaction_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        self._transaction_vote(t)
+        self._storage.tpc_finish(t)
         revid1 = self._transaction_newserial(oid1)
         revid2 = self._transaction_newserial(oid2)
         eq(revid1, revid2)
         # Now attempt to undo the transaction containing two objects
         info = self._storage.undoInfo()
         tid = info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 2)
         self.failUnless(oid1 in oids)
         self.failUnless(oid2 in oids)
@@ -318,13 +335,14 @@
         eq(zodb_unpickle(data), MinPO(51))
         # Like the above, but this time, the second transaction contains only
         # one object.
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
-        self._transaction_store(oid1, revid1, p33, '', self._transaction)
-        self._transaction_store(oid2, revid2, p53, '', self._transaction)
+        self._transaction_store(oid1, revid1, p33, '', t)
+        self._transaction_store(oid2, revid2, p53, '', t)
         # Finish the transaction
-        self._transaction_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        self._transaction_vote(t)
+        self._storage.tpc_finish(t)
         revid1 = self._transaction_newserial(oid1)
         revid2 = self._transaction_newserial(oid2)
         eq(revid1, revid2)
@@ -334,10 +352,11 @@
         # Now attempt to undo the transaction containing two objects
         info = self._storage.undoInfo()
         tid = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         self.failUnless(oid1 in oids)
         self.failUnless(not oid2 in oids)
@@ -357,11 +376,12 @@
         # Start the undo
         info = self._storage.undoInfo()
         tid = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self.assertRaises(POSException.UndoError,
                           self._storage.transactionalUndo,
-                          tid, self._transaction)
-        self._storage.tpc_abort(self._transaction)
+                          tid, t)
+        self._storage.tpc_abort(t)
         # Now have more fun: object1 and object2 are in the same transaction,
         # which we'll try to undo to, but one of them has since modified in
         # different transaction, so the undo should fail.
@@ -372,12 +392,13 @@
         p81, p82, p91, p92 = map(zodb_pickle,
                                  map(MinPO, (81, 82, 91, 92)))
 
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self._transaction_begin()
-        self._transaction_store(oid1, revid1, p81, '', self._transaction)
-        self._transaction_store(oid2, revid2, p91, '', self._transaction)
-        self._transaction_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        self._transaction_store(oid1, revid1, p81, '', t)
+        self._transaction_store(oid2, revid2, p91, '', t)
+        self._transaction_vote(t)
+        self._storage.tpc_finish(t)
         revid1 = self._transaction_newserial(oid1)
         revid2 = self._transaction_newserial(oid2)
         eq(revid1, revid2)
@@ -394,8 +415,9 @@
         self.assertNotEqual(revid2, revid_22)
         info = self._storage.undoInfo()
         tid = info[1]['id']
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         self.assertRaises(POSException.UndoError,
                           self._storage.transactionalUndo,
-                          tid, self._transaction)
-        self._storage.tpc_abort(self._transaction)
+                          tid, t)
+        self._storage.tpc_abort(t)


=== Zope/lib/python/ZODB/tests/TransactionalUndoVersionStorage.py 1.4 => 1.4.88.1 ===
 
 from ZODB import POSException
+from ZODB.Transaction import Transaction
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_unpickle
 
@@ -11,14 +12,17 @@
         oid = self._storage.new_oid()
         version = 'one'
         revid_a = self._dostore(oid, data=MinPO(91))
-        revid_b = self._dostore(oid, revid=revid_a, data=MinPO(92), version=version)
-        revid_c = self._dostore(oid, revid=revid_b, data=MinPO(93), version=version)
+        revid_b = self._dostore(oid, revid=revid_a, data=MinPO(92),
+                                version=version)
+        revid_c = self._dostore(oid, revid=revid_b, data=MinPO(93),
+                                version=version)
         info=self._storage.undoInfo()
         tid=info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         assert len(oids) == 1
         assert oids[0] == oid
         data, revid = self._storage.load(oid, '')
@@ -28,10 +32,11 @@
         assert revid > revid_b and revid > revid_c
         assert zodb_unpickle(data) == MinPO(92)
         # Now commit the version...
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.commitVersion(version, '', self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.commitVersion(version, '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         assert len(oids) == 1
         assert oids[0] == oid
 
@@ -46,10 +51,11 @@
         # ...and undo the commit
         info=self._storage.undoInfo()
         tid=info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         assert len(oids) == 1
         assert oids[0] == oid
         data, revid = self._storage.load(oid, version)
@@ -57,10 +63,11 @@
         data, revid = self._storage.load(oid, '')
         assert zodb_unpickle(data) == MinPO(91)
         # Now abort the version
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.abortVersion(version, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion(version, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         assert len(oids) == 1
         assert oids[0] == oid
         # The object should not exist in the version now, but it should exist
@@ -76,10 +83,11 @@
         # Now undo the abort
         info=self._storage.undoInfo()
         tid=info[0]['id']
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.transactionalUndo(tid, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.transactionalUndo(tid, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         assert len(oids) == 1
         assert oids[0] == oid
         # And the object should be back in versions 'one' and ''


=== Zope/lib/python/ZODB/tests/VersionStorage.py 1.11 => 1.11.30.1 ===
 
 from ZODB import POSException
+from ZODB.Transaction import Transaction
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_unpickle
 
@@ -144,10 +145,11 @@
         
 ##        s1 = self._storage.getSerial(oid)
         # Now abort the version -- must be done in a transaction
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.abortVersion(version, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion(version, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
 ##        s2 = self._storage.getSerial(oid)
 ##        eq(s1, s2) # or self.assert(s2 > s1) ?
         eq(len(oids), 1)
@@ -159,14 +161,15 @@
         eq = self.assertEqual
         oid, version = self._setup_version()
         # Now abort a bogus version
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
 
         #JF# The spec is silent on what happens if you abort or commit
         #JF# a non-existent version. FileStorage consideres this a noop.
         #JF# We can change the spec, but until we do ....
         #JF# self.assertRaises(POSException.VersionError,
         #JF#                   self._storage.abortVersion,
-        #JF#                   'bogus', self._transaction)
+        #JF#                   'bogus', t)
 
         # And try to abort the empty version
         if (hasattr(self._storage, 'supportsTransactionalUndo')
@@ -174,12 +177,12 @@
             # XXX FileStorage used to be broken on this one
             self.assertRaises(POSException.VersionError,
                               self._storage.abortVersion,
-                              '', self._transaction)
+                              '', t)
         
         # But now we really try to abort the version
-        oids = self._storage.abortVersion(version, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        oids = self._storage.abortVersion(version, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
@@ -194,19 +197,24 @@
         oid1, version1 = self._setup_version('one')
         data, revid1 = self._storage.load(oid1, version1)
         eq(zodb_unpickle(data), MinPO(54))
-        self._storage.tpc_begin(self._transaction)
-        self.assertRaises(POSException.VersionCommitError,
-                          self._storage.commitVersion,
-                          'one', 'one', self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        try:
+            self.assertRaises(POSException.VersionCommitError,
+                              self._storage.commitVersion,
+                              'one', 'one', t)
+        finally:
+            self._storage.tpc_abort(t)
 
     def checkModifyAfterAbortVersion(self):
         eq = self.assertEqual
         oid, version = self._setup_version()
         # Now abort the version
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.abortVersion(version, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion(version, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         # Load the object's current state (which gets us the revid)
         data, revid = self._storage.load(oid, '')
         # And modify it a few times
@@ -225,10 +233,11 @@
         data, revid = self._storage.load(oid, '')
         eq(zodb_unpickle(data), MinPO(51))
         # Try committing this version to the empty version
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.commitVersion(version, '', self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.commitVersion(version, '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         data, revid = self._storage.load(oid, '')
         eq(zodb_unpickle(data), MinPO(54))
 
@@ -251,11 +260,12 @@
         eq(zodb_unpickle(data), MinPO(51))
         
         # Okay, now let's commit object1 to version2
-        self._storage.tpc_begin(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
         oids = self._storage.commitVersion(version1, version2,
-                                           self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+                                           t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid1)
         data, revid = self._storage.load(oid1, version2)
@@ -286,10 +296,11 @@
         eq(zodb_unpickle(data), MinPO(51))
 
         # First, let's abort version1
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.abortVersion(version1, self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion(version1, t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid1)
         data, revid = self._storage.load(oid1, '')
@@ -310,10 +321,11 @@
         data, revid = self._storage.load(oid2, version2)
         eq(zodb_unpickle(data), MinPO(54))
         # Okay, now let's commit version2 back to the trunk
-        self._storage.tpc_begin(self._transaction)
-        oids = self._storage.commitVersion(version2, '', self._transaction)
-        self._storage.tpc_vote(self._transaction)
-        self._storage.tpc_finish(self._transaction)
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.commitVersion(version2, '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
         eq(len(oids), 1)
         eq(oids[0], oid2)
         data, revid = self._storage.load(oid1, '')


=== Zope/lib/python/ZODB/tests/testDemoStorage.py 1.2 => 1.2.34.1 ===
     def setUp(self):
         self._storage = ZODB.DemoStorage.DemoStorage()
-        StorageTestBase.StorageTestBase.setUp(self)
+
+    def tearDown(self):
+        self._storage.close()
 
 def test_suite():
     suite = unittest.makeSuite(DemoStorageTests, 'check')


=== Zope/lib/python/ZODB/tests/testFileStorage.py 1.13 => 1.13.32.1 ===
+
 import ZODB.FileStorage
 import sys, os, unittest
+import errno
+from ZODB.Transaction import Transaction
 
 from ZODB.tests import StorageTestBase, BasicStorage, \
      TransactionalUndoStorage, VersionStorage, \
      TransactionalUndoVersionStorage, PackableStorage, \
      Synchronization, ConflictResolution, HistoryStorage, \
-     IteratorStorage, Corruption, RevisionStorage, PersistentStorage
+     IteratorStorage, Corruption, RevisionStorage, PersistentStorage, \
+     MTStorage, ReadOnlyStorage
 
 class FileStorageTests(
     StorageTestBase.StorageTestBase,
@@ -19,7 +24,10 @@
     ConflictResolution.ConflictResolvingStorage,
     HistoryStorage.HistoryStorage,
     IteratorStorage.IteratorStorage,
+    IteratorStorage.ExtendedIteratorStorage,
     PersistentStorage.PersistentStorage,
+    MTStorage.MTStorage,
+    ReadOnlyStorage.ReadOnlyStorage
     ):
 
     def open(self, **kwargs):
@@ -32,19 +40,89 @@
 
     def setUp(self):
         self.open(create=1)
-        StorageTestBase.StorageTestBase.setUp(self)
 
     def tearDown(self):
-        StorageTestBase.StorageTestBase.tearDown(self)
+        self._storage.close()
         for ext in '', '.old', '.tmp', '.lock', '.index':
             path = 'FileStorageTests.fs' + ext
             if os.path.exists(path):
                 os.remove(path)
 
+class FileStorageRecoveryTest(
+    StorageTestBase.StorageTestBase,
+    IteratorStorage.IteratorDeepCompare,
+    ):
+
+    def setUp(self):
+        self._storage = ZODB.FileStorage.FileStorage('Source.fs')
+        self._dst = ZODB.FileStorage.FileStorage('Dest.fs')
+
+    def tearDown(self):
+        self._storage.close()
+        self._dst.close()
+        for ext in '', '.old', '.tmp', '.lock', '.index':
+            for fs in 'Source', 'Dest':
+                path = fs + '.fs' + ext
+                try:
+                    os.remove(path)
+                except OSError, e:
+                    if e.errno <> errno.ENOENT: raise
+
+    def checkSimpleRecovery(self):
+        oid = self._storage.new_oid()
+        revid = self._dostore(oid, data=11)
+        revid = self._dostore(oid, revid=revid, data=12)
+        revid = self._dostore(oid, revid=revid, data=13)
+        self._dst.copyTransactionsFrom(self._storage)
+        self.compare(self._storage, self._dst)
+
+    def checkRecoveryAcrossVersions(self):
+        oid = self._storage.new_oid()
+        revid = self._dostore(oid, data=21)
+        revid = self._dostore(oid, revid=revid, data=22)
+        revid = self._dostore(oid, revid=revid, data=23, version='one')
+        revid = self._dostore(oid, revid=revid, data=34, version='one')
+        # Now commit the version
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        self._storage.commitVersion('one', '', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
+        self._dst.copyTransactionsFrom(self._storage)
+        self.compare(self._storage, self._dst)
+
+    def checkRecoverAbortVersion(self):
+        oid = self._storage.new_oid()
+        revid = self._dostore(oid, data=21, version="one")
+        revid = self._dostore(oid, revid=revid, data=23, version='one')
+        revid = self._dostore(oid, revid=revid, data=34, version='one')
+        # Now abort the version and the creation
+        t = Transaction()
+        self._storage.tpc_begin(t)
+        oids = self._storage.abortVersion('one', t)
+        self._storage.tpc_vote(t)
+        self._storage.tpc_finish(t)
+        self.assertEqual(oids, [oid])
+        self._dst.copyTransactionsFrom(self._storage)
+        self.compare(self._storage, self._dst)
+        # Also make sure the the last transaction has a data record
+        # with None for its data attribute, because we've undone the
+        # object.
+        for s in self._storage, self._dst:
+            iter = s.iterator()
+            for trans in iter:
+                pass # iterate until we get the last one
+            data = trans[0]
+            self.assertRaises(IndexError, lambda i:trans[i], 1)
+            self.assertEqual(data.oid, oid)
+            self.assertEqual(data.data, None)
+                
+
 def test_suite():
     suite = unittest.makeSuite(FileStorageTests, 'check')
     suite2 = unittest.makeSuite(Corruption.FileStorageCorruptTests, 'check')
     suite.addTest(suite2)
+    suite.addTest(suite3)
     return suite
 
 def main():


=== Zope/lib/python/ZODB/tests/testMappingStorage.py 1.1 => 1.1.34.1 ===
     def setUp(self):
         self._storage = ZODB.MappingStorage.MappingStorage()
-        StorageTestBase.StorageTestBase.setUp(self)
+
+    def tearDown(self):
+        self._storage.close()
 
 def test_suite():
     suite = unittest.makeSuite(MappingStorageTests, 'check')