[Zodb-checkins] CVS: ZODB3/ZODB/tests - TransactionalUndoStorage.py:1.22.2.1
Jeremy Hylton
jeremy@zope.com
Fri, 18 Oct 2002 15:39:59 -0400
Update of /cvs-repository/ZODB3/ZODB/tests
In directory cvs.zope.org:/tmp/cvs-serv8403/ZODB/tests
Modified Files:
Tag: ZODB3-3_1-branch
TransactionalUndoStorage.py
Log Message:
Backport for trunk: data_txn attribute for iterator() and cleanups.
=== ZODB3/ZODB/tests/TransactionalUndoStorage.py 1.22 => 1.22.2.1 ===
--- ZODB3/ZODB/tests/TransactionalUndoStorage.py:1.22 Wed Sep 25 18:05:16 2002
+++ ZODB3/ZODB/tests/TransactionalUndoStorage.py Fri Oct 18 15:39:58 2002
@@ -2,13 +2,14 @@
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
@@ -57,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()
@@ -117,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
@@ -147,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
@@ -178,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
@@ -231,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
@@ -301,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
@@ -371,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):
@@ -428,6 +446,7 @@
self._storage.transactionalUndo,
tid, t)
self._storage.tpc_abort(t)
+ self._iterate()
def checkTransactionalUndoAfterPack(self):
eq = self.assertEqual
@@ -466,6 +485,7 @@
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
@@ -521,3 +541,92 @@
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)
+ 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)
+ 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 - 1 - 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)