[Zodb-checkins] CVS: Zope/lib/python/ZODB/tests - dangle.py:1.1.4.1 TransactionalUndoStorage.py:1.21.4.2 TransactionalUndoVersionStorage.py:1.8.4.1

Chris McDonough chrism@zope.com
Sat, 26 Oct 2002 15:52:21 -0400


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

Modified Files:
      Tag: chrism-install-branch
	TransactionalUndoStorage.py TransactionalUndoVersionStorage.py 
Added Files:
      Tag: chrism-install-branch
	dangle.py 
Log Message:
Merge with HEAD.  Again, sorry for the spew (what's left of it... someone seems to have filtered some of this branch's checkins out).


=== Added File Zope/lib/python/ZODB/tests/dangle.py ===
#! /usr/bin/env python

##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################

"""Functional test to produce a dangling reference."""

import time

from ZODB.FileStorage import FileStorage
from ZODB import DB

from Persistence import Persistent

class P(Persistent):
    pass

def create_dangling_ref(db):
    rt = db.open().root()

    rt[1] = o1 = P()
    get_transaction().note("create o1")
    get_transaction().commit()

    rt[2] = o2 = P()
    get_transaction().note("create o2")
    get_transaction().commit()

    c = o1.child = P()
    get_transaction().note("set child on o1")
    get_transaction().commit()

    o1.child = P()
    get_transaction().note("replace child on o1")
    get_transaction().commit()

    time.sleep(2)
    # The pack should remove the reference to c, because it is no
    # longer referenced from o1.  But the object still exists and has
    # an oid, so a new commit of it won't create a new object.
    db.pack()

    print repr(c._p_oid)
    o2.child = c
    get_transaction().note("set child on o2")
    get_transaction().commit()

def main():
    fs = FileStorage("dangle.fs")
    db = DB(fs)
    create_dangling_ref(db)
    db.close()
    
if __name__ == "__main__":
    main()


=== Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py 1.21.4.1 => 1.21.4.2 ===
--- Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py:1.21.4.1	Sat Sep 28 21:40:37 2002
+++ Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py	Sat Oct 26 15:51:49 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+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/TransactionalUndoVersionStorage.py 1.8 => 1.8.4.1 ===
--- Zope/lib/python/ZODB/tests/TransactionalUndoVersionStorage.py:1.8	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/tests/TransactionalUndoVersionStorage.py	Sat Oct 26 15:51:50 2002
@@ -30,6 +30,8 @@
         return self._dostore(*args, **kwargs)
 
     def checkUndoInVersion(self):
+        eq = self.assertEqual
+        unless = self.failUnless
         oid = self._storage.new_oid()
         version = 'one'
         revid_a = self._dostore(oid, data=MinPO(91))
@@ -44,31 +46,31 @@
         oids = self._storage.transactionalUndo(tid, t)
         self._storage.tpc_vote(t)
         self._storage.tpc_finish(t)
-        assert len(oids) == 1
-        assert oids[0] == oid
+        eq(len(oids), 1)
+        eq(oids[0], oid)
         data, revid = self._storage.load(oid, '')
-        assert revid == revid_a
-        assert zodb_unpickle(data) == MinPO(91)
+        eq(revid, revid_a)
+        eq(zodb_unpickle(data), MinPO(91))
         data, revid = self._storage.load(oid, version)
-        assert revid > revid_b and revid > revid_c
-        assert zodb_unpickle(data) == MinPO(92)
+        unless(revid > revid_b and revid > revid_c)
+        eq(zodb_unpickle(data), MinPO(92))
         # Now commit the version...
         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
+        eq(len(oids), 1)
+        eq(oids[0], oid)
 
         #JF# No, because we fall back to non-version data.
         #JF# self.assertRaises(POSException.VersionError,
         #JF#                   self._storage.load,
         #JF#                   oid, version)
         data, revid = self._storage.load(oid, version)
-        assert zodb_unpickle(data) == MinPO(92)
+        eq(zodb_unpickle(data), MinPO(92))
         data, revid = self._storage.load(oid, '')
-        assert zodb_unpickle(data) == MinPO(92)
+        eq(zodb_unpickle(data), MinPO(92))
         # ...and undo the commit
         info=self._storage.undoInfo()
         tid=info[0]['id']
@@ -77,20 +79,20 @@
         oids = self._storage.transactionalUndo(tid, t)
         self._storage.tpc_vote(t)
         self._storage.tpc_finish(t)
-        assert len(oids) == 1
-        assert oids[0] == oid
+        eq(len(oids), 1)
+        eq(oids[0], oid)
         data, revid = self._storage.load(oid, version)
-        assert zodb_unpickle(data) == MinPO(92)
+        eq(zodb_unpickle(data), MinPO(92))
         data, revid = self._storage.load(oid, '')
-        assert zodb_unpickle(data) == MinPO(91)
+        eq(zodb_unpickle(data), MinPO(91))
         # Now abort the version
         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
+        eq(len(oids), 1)
+        eq(oids[0], oid)
         # The object should not exist in the version now, but it should exist
         # in the non-version
         #JF# No, because we fall back
@@ -98,9 +100,9 @@
         #JF#                   self._storage.load,
         #JF#                   oid, version)
         data, revid = self._storage.load(oid, version)
-        assert zodb_unpickle(data) == MinPO(91)
+        eq(zodb_unpickle(data), MinPO(91))
         data, revid = self._storage.load(oid, '')
-        assert zodb_unpickle(data) == MinPO(91)
+        eq(zodb_unpickle(data), MinPO(91))
         # Now undo the abort
         info=self._storage.undoInfo()
         tid=info[0]['id']
@@ -109,13 +111,13 @@
         oids = self._storage.transactionalUndo(tid, t)
         self._storage.tpc_vote(t)
         self._storage.tpc_finish(t)
-        assert len(oids) == 1
-        assert oids[0] == oid
+        eq(len(oids), 1)
+        eq(oids[0], oid)
         # And the object should be back in versions 'one' and ''
         data, revid = self._storage.load(oid, version)
-        assert zodb_unpickle(data) == MinPO(92)
+        eq(zodb_unpickle(data), MinPO(92))
         data, revid = self._storage.load(oid, '')
-        assert zodb_unpickle(data) == MinPO(91)
+        eq(zodb_unpickle(data), MinPO(91))
 
     def checkUndoCommitVersion(self):
         def load_value(oid, version=''):