[Zodb-checkins] CVS: Zope/lib/python/ZODB/tests - ConflictResolution.py:1.8.6.1 MTStorage.py:1.4.6.1 TransactionalUndoStorage.py:1.21.6.1 testTransaction.py:1.11.6.1 testZODB.py:1.4.6.1

Jeremy Hylton jeremy@zope.com
Tue, 12 Nov 2002 16:13:59 -0500


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

Modified Files:
      Tag: Zope-2_6-branch
	ConflictResolution.py MTStorage.py TransactionalUndoStorage.py 
	testTransaction.py testZODB.py 
Log Message:
Sync Zope 2.6 and ZODB 3.1 release branches.

ZODB deadlock prevention code.
Bug in ConflictResolution bad_classes handling.
Don't let exceptions propagate out of ConflictResolution.
Add data_txn atribute to records returned by storage iterators.
Other sundry changes.



=== Zope/lib/python/ZODB/tests/ConflictResolution.py 1.8 => 1.8.6.1 ===
--- Zope/lib/python/ZODB/tests/ConflictResolution.py:1.8	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/tests/ConflictResolution.py	Tue Nov 12 16:13:58 2002
@@ -104,7 +104,7 @@
         # pickle is to commit two different transactions relative to
         # revid1 that add two to _value.
         revid2 = self._dostoreNP(oid, revid=revid1, data=zodb_pickle(obj))
-        self.assertRaises(AttributeError,
+        self.assertRaises(ConflictError,
                           self._dostoreNP,
                           oid, revid=revid1, data=zodb_pickle(obj))
 
@@ -122,7 +122,7 @@
         # pickle is to commit two different transactions relative to
         # revid1 that add two to _value.
         revid2 = self._dostoreNP(oid, revid=revid1, data=zodb_pickle(obj))
-        self.assertRaises(TypeError,
+        self.assertRaises(ConflictError,
                           self._dostoreNP,
                           oid, revid=revid1, data=zodb_pickle(obj))
 


=== Zope/lib/python/ZODB/tests/MTStorage.py 1.4 => 1.4.6.1 ===
--- Zope/lib/python/ZODB/tests/MTStorage.py:1.4	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/tests/MTStorage.py	Tue Nov 12 16:13:58 2002
@@ -170,9 +170,9 @@
         for t in threads:
             t.start()
         for t in threads:
-            t.join(10)
+            t.join(60)
         for t in threads:
-            self.failIf(t.isAlive())
+            self.failIf(t.isAlive(), "thread failed to finish in 60 seconds")
 
     def check2ZODBThreads(self):
         db = ZODB.DB(self._storage)


=== Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py 1.21 => 1.21.6.1 ===
--- Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py:1.21	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py	Tue Nov 12 16:13:58 2002
@@ -2,19 +2,25 @@
 
 Any storage that supports transactionalUndo() must pass these tests.
 """
+from __future__ import nested_scopes
 
 import time
 import types
 from ZODB import POSException
 from ZODB.Transaction import Transaction
 from ZODB.referencesf import referencesf
-from ZODB.utils import u64
+from ZODB.utils import u64, p64
+from ZODB import DB
 
+from Persistence import Persistent
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
 
 ZERO = '\0'*8
 
+class C(Persistent):
+    pass
+
 class TransactionalUndoStorage:
 
     def _transaction_begin(self):
@@ -52,6 +58,17 @@
             newrevs[oid] = self._transaction_newserial(oid)
         return newrevs
 
+    def _iterate(self):
+        """Iterate over the storage in its final state."""
+        # This is testing that the iterator() code works correctly.
+        # The hasattr() guards against ZEO, which doesn't support iterator.
+        if not hasattr(self._storage, "iterator"):
+            return
+        iter = self._storage.iterator()
+        for txn in iter:
+            for rec in txn:
+                pass
+
     def checkSimpleTransactionalUndo(self):
         eq = self.assertEqual
         oid = self._storage.new_oid()
@@ -112,6 +129,7 @@
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
         eq(zodb_unpickle(data), MinPO(23))
+        self._iterate()
 
     def checkUndoCreationBranch1(self):
         eq = self.assertEqual
@@ -142,6 +160,7 @@
         eq(len(oids), 1)
         eq(oids[0], oid)
         self.assertRaises(KeyError, self._storage.load, oid, '')
+        self._iterate()
 
     def checkUndoCreationBranch2(self):
         eq = self.assertEqual
@@ -173,6 +192,7 @@
         eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
         eq(zodb_unpickle(data), MinPO(12))
+        self._iterate()
 
     def checkTwoObjectUndo(self):
         eq = self.assertEqual
@@ -226,6 +246,7 @@
         eq(zodb_unpickle(data), MinPO(31))
         data, revid2 = self._storage.load(oid2, '')
         eq(zodb_unpickle(data), MinPO(51))
+        self._iterate()
 
     def checkTwoObjectUndoAtOnce(self):
         # Convenience
@@ -296,6 +317,7 @@
         eq(zodb_unpickle(data), MinPO(32))
         data, revid2 = self._storage.load(oid2, '')
         eq(zodb_unpickle(data), MinPO(52))
+        self._iterate()
 
     def checkTwoObjectUndoAgain(self):
         eq = self.assertEqual
@@ -366,6 +388,7 @@
         eq(zodb_unpickle(data), MinPO(33))
         data, revid2 = self._storage.load(oid2, '')
         eq(zodb_unpickle(data), MinPO(54))
+        self._iterate()
 
 
     def checkNotUndoable(self):
@@ -423,6 +446,7 @@
                           self._storage.transactionalUndo,
                           tid, t)
         self._storage.tpc_abort(t)
+        self._iterate()
 
     def checkTransactionalUndoAfterPack(self):
         eq = self.assertEqual
@@ -461,3 +485,148 @@
         data, revid = self._storage.load(oid, '')
         # The object must now be at the second state
         eq(zodb_unpickle(data), MinPO(52))
+        self._iterate()
+
+    def checkTransactionalUndoAfterPackWithObjectUnlinkFromRoot(self):
+        eq = self.assertEqual
+        db = DB(self._storage)
+        conn = db.open()
+        root = conn.root()
+
+        o1 = C()
+        o2 = C()
+        root['obj'] = o1
+        o1.obj = o2
+        txn = get_transaction()
+        txn.note('o1 -> o2')
+        txn.commit()
+        now = packtime = time.time()
+        while packtime <= now:
+            packtime = time.time()
+
+        o3 = C()
+        o2.obj = o3
+        txn = get_transaction()
+        txn.note('o1 -> o2 -> o3')
+        txn.commit()
+
+        o1.obj = o3
+        txn = get_transaction()
+        txn.note('o1 -> o3')
+        txn.commit()
+
+        log = self._storage.undoLog()
+        eq(len(log), 4)
+        for entry in zip(log, ('o1 -> o3', 'o1 -> o2 -> o3',
+                               'o1 -> o2', 'initial database creation')):
+            eq(entry[0]['description'], entry[1])
+
+        self._storage.pack(packtime, referencesf)
+
+        log = self._storage.undoLog()
+        for entry in zip(log, ('o1 -> o3', 'o1 -> o2 -> o3')):
+            eq(entry[0]['description'], entry[1])
+
+        tid = log[0]['id']
+        db.undo(tid)
+        txn = get_transaction()
+        txn.note('undo')
+        txn.commit()
+        # undo does a txn-undo, but doesn't invalidate
+        conn.sync()
+
+        log = self._storage.undoLog()
+        for entry in zip(log, ('undo', 'o1 -> o3', 'o1 -> o2 -> o3')):
+            eq(entry[0]['description'], entry[1])
+
+        eq(o1.obj, o2)
+        eq(o1.obj.obj, o3)
+        self._iterate()
+
+    def checkTransactionalUndoIterator(self):
+        # check that data_txn set in iterator makes sense
+        if not hasattr(self._storage, "iterator"):
+            return
+
+        s = self._storage
+
+        BATCHES = 4
+        OBJECTS = 4
+
+        orig = []
+        for i in range(BATCHES):
+            t = Transaction()
+            tid = p64(i + 1)
+            s.tpc_begin(t, tid)
+            for j in range(OBJECTS):
+                oid = s.new_oid()
+                obj = MinPO(i * OBJECTS + j)
+                revid = s.store(oid, None, zodb_pickle(obj), '', t)
+                orig.append((tid, oid, revid))
+            s.tpc_vote(t)
+            s.tpc_finish(t)
+
+        i = 0
+        for tid, oid, revid in orig:
+            self._dostore(oid, revid=revid, data=MinPO(revid),
+                          description="update %s" % i)
+
+        # Undo the OBJECTS transactions that modified objects created
+        # in the ith original transaction.
+
+        def undo(i):
+            info = s.undoInfo()
+            t = Transaction()
+            s.tpc_begin(t)
+            base = i * OBJECTS + i
+            for j in range(OBJECTS):
+                tid = info[base + j]['id']
+                s.transactionalUndo(tid, t)
+            s.tpc_vote(t)
+            s.tpc_finish(t)
+        
+        for i in range(BATCHES):
+            undo(i)
+
+        # There are now (2 + OBJECTS) * BATCHES transactions:
+        #     BATCHES original transactions, followed by
+        #     OBJECTS * BATCHES modifications, followed by
+        #     BATCHES undos
+
+        iter = s.iterator()
+        offset = 0
+
+        eq = self.assertEqual
+
+        for i in range(BATCHES):
+            txn = iter[offset]
+            offset += 1
+            
+            tid = p64(i + 1)
+            eq(txn.tid, tid)
+
+            L1 = [(rec.oid, rec.serial, rec.data_txn) for rec in txn]
+            L2 = [(oid, revid, None) for _tid, oid, revid in orig
+                  if _tid == tid]
+            
+            eq(L1, L2)
+
+        for i in range(BATCHES * OBJECTS):
+            txn = iter[offset]
+            offset += 1
+            eq(len([rec for rec in txn if rec.data_txn is None]), 1)
+
+        for i in range(BATCHES):
+            txn = iter[offset]
+            offset += 1
+
+            # The undos are performed in reverse order.
+            otid = p64(BATCHES - i)
+            L1 = [(rec.oid, rec.data_txn) for rec in txn]
+            L2 = [(oid, otid) for _tid, oid, revid in orig
+                  if _tid == otid]
+            L1.sort()
+            L2.sort()
+            eq(L1, L2)
+
+        self.assertRaises(IndexError, iter.__getitem__, offset)


=== Zope/lib/python/ZODB/tests/testTransaction.py 1.11 => 1.11.6.1 ===


=== Zope/lib/python/ZODB/tests/testZODB.py 1.4 => 1.4.6.1 ===
--- Zope/lib/python/ZODB/tests/testZODB.py:1.4	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/tests/testZODB.py	Tue Nov 12 16:13:58 2002
@@ -94,6 +94,16 @@
         self._storage.close()
         removefs("ZODBTests.fs")
 
+    def checkVersionOnly(self):
+        # Make sure the changes to make empty transactions a no-op
+        # still allow things like abortVersion().  This should work
+        # because abortVersion() calls tpc_begin() itself.
+        r = self._db.open("version").root()
+        r[1] = 1
+        get_transaction().commit()
+        self._db.abortVersion("version")
+        get_transaction().commit()
+
 def test_suite():
     return unittest.makeSuite(ZODBTests, 'check')