Commit 58cfe930 authored by Jeremy Hylton's avatar Jeremy Hylton

Fix tests to work correctly with conflict resolution.

Add new tests for conflict resolution.

The old blanket try-except for conflict resolution was hiding some
bugs caused by the pickles used in the test suite.  The conflict
resolution code imposes some restrictions on the format of pickles.
Basically, the conflict resolution requires that the storage API only
accept a pickles that constructed according to the ZODB rules.

XXX This new restriction sounds unfortunate, but it would require a
substantial change to conflict resolution to remove it.

The key changes to the test suite are to store only persistent objects
and to format the pickles using the standard ZODB format.  All tests
now use ZODB.tests.MinPO.MinPO instances for data.  The pickling is
down with zodb_pickle() and zodb_unpickle() defined in
StorageTestBase.

Add conflict resolution tests to testFileStorage.  (They pass.)
parent 95f9483c
......@@ -7,8 +7,10 @@
from ZODB.Transaction import Transaction
from ZODB import POSException
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle
ZERO = '\0'*8
import pickle
......@@ -70,16 +72,16 @@ class BasicStorage:
def checkNonVersionStoreAndLoad(self):
oid = self._storage.new_oid()
self._dostore(oid=oid, data=7)
self._dostore(oid=oid, data=MinPO(7))
data, revid = self._storage.load(oid, '')
value = pickle.loads(data)
assert value == 7
value = zodb_unpickle(data)
assert value == MinPO(7)
# Now do a bunch of updates to an object
for i in range(13, 22):
revid = self._dostore(oid, revid=revid, data=i)
revid = self._dostore(oid, revid=revid, data=MinPO(i))
# Now get the latest revision of the object
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 21
assert zodb_unpickle(data) == MinPO(21)
def checkNonVersionModifiedInVersion(self):
oid = self._storage.new_oid()
......@@ -91,18 +93,18 @@ class BasicStorage:
revid = ZERO
revisions = {}
for i in range(31, 38):
revid = self._dostore(oid, revid=revid, data=i)
revisions[revid] = i
revid = self._dostore(oid, revid=revid, data=MinPO(i))
revisions[revid] = MinPO(i)
# Now make sure all the revisions have the correct value
for revid, value in revisions.items():
data = self._storage.loadSerial(oid, revid)
assert pickle.loads(data) == value
assert zodb_unpickle(data) == value
def checkConflicts(self):
oid = self._storage.new_oid()
revid1 = self._dostore(oid, data=11)
revid2 = self._dostore(oid, revid=revid1, data=12)
revid1 = self._dostore(oid, data=MinPO(11))
revid2 = self._dostore(oid, revid=revid1, data=MinPO(12))
self.assertRaises(POSException.ConflictError,
self._dostore,
oid, revid=revid1, data=13)
oid, revid=revid1, data=MinPO(13))
"""Tests for application-level conflict resolution."""
from ZODB.Transaction import Transaction
from ZODB.POSException import ConflictError
from Persistence import Persistent
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
import sys
import types
from cPickle import Pickler, Unpickler
from cStringIO import StringIO
class PCounter(Persistent):
_value = 0
def __repr__(self):
return "<PCounter %d>" % self._value
def inc(self):
self._value = self._value + 1
def _p_resolveConflict(self, oldState, savedState, newState):
savedDiff = savedState['_value'] - oldState['_value']
newDiff = newState['_value'] - oldState['_value']
oldState['_value'] = oldState['_value'] + savedDiff + newDiff
return oldState
# XXX What if _p_resolveConflict _thinks_ it resolved the
# conflict, but did something wrong?
class PCounter2(PCounter):
def _p_resolveConflict(self, oldState, savedState, newState):
raise ConflictError
class PCounter3(PCounter):
def _p_resolveConflict(self, oldState, savedState, newState):
raise AttributeError, "no attribute"
class ConflictResolvingStorage:
def checkResolve(self):
obj = PCounter()
obj.inc()
oid = self._storage.new_oid()
revid1 = self._dostoreNP(oid, data=zodb_pickle(obj))
obj.inc()
obj.inc()
# The effect of committing two transactions with the same
# 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))
revid3 = self._dostoreNP(oid, revid=revid1, data=zodb_pickle(obj))
data, serialno = self._storage.load(oid, '')
inst = zodb_unpickle(data)
self.assert_(inst._value == 5)
def checkUnresolvable(self):
obj = PCounter2()
obj.inc()
oid = self._storage.new_oid()
revid1 = self._dostoreNP(oid, data=zodb_pickle(obj))
obj.inc()
obj.inc()
# The effect of committing two transactions with the same
# 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(ConflictError,
self._dostoreNP,
oid, revid=revid1, data=zodb_pickle(obj))
def checkBuggyResolve(self):
obj = PCounter3()
obj.inc()
oid = self._storage.new_oid()
revid1 = self._dostoreNP(oid, data=zodb_pickle(obj))
obj.inc()
obj.inc()
# The effect of committing two transactions with the same
# 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._dostoreNP,
oid, revid=revid1, data=zodb_pickle(obj))
# XXX test conflict error raised during undo
......@@ -4,11 +4,69 @@
# store transaction for a single object revision.
import pickle
import string
import sys
import types
import unittest
from cPickle import Pickler, Unpickler
from cStringIO import StringIO
from ZODB.Transaction import Transaction
from ZODB.tests.MinPO import MinPO
ZERO = '\0'*8
def zodb_pickle(obj):
f = StringIO()
p = Pickler(f, 1)
klass = obj.__class__
assert not hasattr(obj, '__getinitargs__'), "not ready for constructors"
args = None
mod = getattr(klass, '__module__', None)
if mod is not None:
klass = mod, klass.__name__
state = obj.__getstate__()
p.dump((klass, args))
p.dump(state)
return f.getvalue(1)
def zodb_unpickle(data):
f = StringIO(data)
u = Unpickler(f)
klass_info = u.load()
if isinstance(klass_info, types.TupleType):
if isinstance(klass_info[0], types.TupleType):
modname, klassname = klass_info[0]
args = klass_info[1]
else:
modname, klassname = klass_info
args = None
if modname == "__main__":
ns = globals()
else:
mod = import_helper(modname)
ns = mod.__dict__
try:
klass = ns[klassname]
except KeyError:
print >> sys.stderr, "can't find %s in %s" % (klassname,
repr(ns))
inst = klass()
else:
raise ValueError, "expected class info: %s" % repr(klass_info)
state = u.load()
inst.__setstate__(state)
return inst
def import_helper(name):
mod = __import__(name)
for part in string.split(name, ".")[1:]:
mod = getattr(mod, part)
return mod
class StorageTestBase(unittest.TestCase):
......@@ -39,9 +97,12 @@ class StorageTestBase(unittest.TestCase):
if revid is None:
revid = ZERO
if data is None:
data = 7
data = MinPO(7)
if type(data) == types.IntType:
data = MinPO(data)
if not already_pickled:
data = pickle.dumps(data)
## data = pickle.dumps(data)
data = zodb_pickle(data)
if version is None:
version = ''
# Begin the transaction
......
# Check transactionalUndo(). Any storage that supports transactionalUndo()
# must pass these tests.
import pickle
import types
from ZODB import POSException
ZERO = '\0'*8
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
ZERO = '\0'*8
class TransactionalUndoStorage:
......@@ -47,9 +48,9 @@ class TransactionalUndoStorage:
def checkSimpleTransactionalUndo(self):
oid = self._storage.new_oid()
revid = self._dostore(oid, data=23)
revid = self._dostore(oid, revid=revid, data=24)
revid = self._dostore(oid, revid=revid, data=25)
revid = self._dostore(oid, data=MinPO(23))
revid = self._dostore(oid, revid=revid, data=MinPO(24))
revid = self._dostore(oid, revid=revid, data=MinPO(25))
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -62,7 +63,7 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 24
assert zodb_unpickle(data) == MinPO(24)
# Do another one
info = self._storage.undoInfo()
tid = info[2]['id']
......@@ -74,7 +75,7 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 23
assert zodb_unpickle(data) == MinPO(23)
# Try to undo the first record
info = self._storage.undoInfo()
tid = info[4]['id']
......@@ -99,12 +100,12 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 23
assert zodb_unpickle(data) == MinPO(23)
def checkUndoCreationBranch1(self):
oid = self._storage.new_oid()
revid = self._dostore(oid, data=11)
revid = self._dostore(oid, revid=revid, data=12)
revid = self._dostore(oid, data=MinPO(11))
revid = self._dostore(oid, revid=revid, data=MinPO(12))
# Undo the last transaction
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -115,7 +116,7 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 11
assert zodb_unpickle(data) == MinPO(11)
# Now from here, we can either redo the last undo, or undo the object
# creation. Let's undo the object creation.
info = self._storage.undoInfo()
......@@ -130,8 +131,8 @@ class TransactionalUndoStorage:
def checkUndoCreationBranch2(self):
oid = self._storage.new_oid()
revid = self._dostore(oid, data=11)
revid = self._dostore(oid, revid=revid, data=12)
revid = self._dostore(oid, data=MinPO(11))
revid = self._dostore(oid, revid=revid, data=MinPO(12))
# Undo the last transaction
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -142,7 +143,7 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 11
assert zodb_unpickle(data) == MinPO(11)
# Now from here, we can either redo the last undo, or undo the object
# creation. Let's redo the last undo
info = self._storage.undoInfo()
......@@ -154,11 +155,12 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 12
assert zodb_unpickle(data) == MinPO(12)
def checkTwoObjectUndo(self):
# Convenience
p31, p32, p51, p52 = map(pickle.dumps, (31, 32, 51, 52))
p31, p32, p51, p52 = map(zodb_pickle,
map(MinPO, (31, 32, 51, 52)))
oid1 = self._storage.new_oid()
oid2 = self._storage.new_oid()
revid1 = revid2 = ZERO
......@@ -186,9 +188,9 @@ class TransactionalUndoStorage:
assert revid1 == revid2
# Make sure the objects have the current value
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 32
assert zodb_unpickle(data) == MinPO(32)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 52
assert zodb_unpickle(data) == MinPO(52)
# Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -199,14 +201,15 @@ class TransactionalUndoStorage:
assert len(oids) == 2
assert oid1 in oids and oid2 in oids
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 31
assert zodb_unpickle(data) == MinPO(31)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
def checkTwoObjectUndoAtOnce(self):
# Convenience
p30, p31, p32, p50, p51, p52 = map(pickle.dumps,
(30, 31, 32, 50, 51, 52))
p30, p31, p32, p50, p51, p52 = map(zodb_pickle,
map(MinPO,
(30, 31, 32, 50, 51, 52)))
oid1 = self._storage.new_oid()
oid2 = self._storage.new_oid()
revid1 = revid2 = ZERO
......@@ -230,9 +233,9 @@ class TransactionalUndoStorage:
assert revid1 == revid2
# Make sure the objects have the current value
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 32
assert zodb_unpickle(data) == MinPO(32)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 52
assert zodb_unpickle(data) == MinPO(52)
# Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -249,9 +252,9 @@ class TransactionalUndoStorage:
assert len(oids1) == 2
assert oid1 in oids and oid2 in oids
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 30
assert zodb_unpickle(data) == MinPO(30)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 50
assert zodb_unpickle(data) == MinPO(50)
# Now try to undo the one we just did to undo, whew
info = self._storage.undoInfo()
tid = info[0]['id']
......@@ -262,18 +265,19 @@ class TransactionalUndoStorage:
assert len(oids) == 2
assert oid1 in oids and oid2 in oids
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 32
assert zodb_unpickle(data) == MinPO(32)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 52
assert zodb_unpickle(data) == MinPO(52)
def checkTwoObjectUndoAgain(self):
p32, p33, p52, p53 = map(pickle.dumps, (32, 33, 52, 53))
p32, p33, p52, p53 = map(zodb_pickle,
map(MinPO, (32, 33, 52, 53)))
# Like the above, but the first revision of the objects are stored in
# different transactions.
oid1 = self._storage.new_oid()
oid2 = self._storage.new_oid()
revid1 = self._dostore(oid1, data=31)
revid2 = self._dostore(oid2, data=51)
revid1 = self._dostore(oid1, data=MinPO(31))
revid2 = self._dostore(oid2, data=MinPO(51))
# Update those same two objects
self._storage.tpc_begin(self._transaction)
self._transaction_begin()
......@@ -295,9 +299,9 @@ class TransactionalUndoStorage:
assert len(oids) == 2
assert oid1 in oids and oid2 in oids
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 31
assert zodb_unpickle(data) == MinPO(31)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
# Like the above, but this time, the second transaction contains only
# one object.
self._storage.tpc_begin(self._transaction)
......@@ -311,8 +315,8 @@ class TransactionalUndoStorage:
revid2 = self._transaction_newserial(oid2)
assert revid1 == revid2
# Update in different transactions
revid1 = self._dostore(oid1, revid=revid1, data=34)
revid2 = self._dostore(oid2, revid=revid2, data=54)
revid1 = self._dostore(oid1, revid=revid1, data=MinPO(34))
revid2 = self._dostore(oid2, revid=revid2, data=MinPO(54))
# Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo()
tid = info[1]['id']
......@@ -323,17 +327,17 @@ class TransactionalUndoStorage:
assert len(oids) == 1
assert oid1 in oids and not oid2 in oids
data, revid1 = self._storage.load(oid1, '')
assert pickle.loads(data) == 33
assert zodb_unpickle(data) == MinPO(33)
data, revid2 = self._storage.load(oid2, '')
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
def checkNotUndoable(self):
# Set things up so we've got a transaction that can't be undone
oid = self._storage.new_oid()
revid_a = self._dostore(oid, data=51)
revid_b = self._dostore(oid, revid=revid_a, data=52)
revid_c = self._dostore(oid, revid=revid_b, data=53)
revid_a = self._dostore(oid, data=MinPO(51))
revid_b = self._dostore(oid, revid=revid_a, data=MinPO(52))
revid_c = self._dostore(oid, revid=revid_b, data=MinPO(53))
# Start the undo
info = self._storage.undoInfo()
tid = info[1]['id']
......@@ -349,7 +353,8 @@ class TransactionalUndoStorage:
revid1 = revid_c
oid2 = self._storage.new_oid()
revid2 = ZERO
p81, p82, p91, p92 = map(pickle.dumps, (81, 82, 91, 92))
p81, p82, p91, p92 = map(zodb_pickle,
map(MinPO, (81, 82, 91, 92)))
self._storage.tpc_begin(self._transaction)
self._transaction_begin()
......@@ -362,12 +367,12 @@ class TransactionalUndoStorage:
assert revid1 == revid2
# Make sure the objects have the expected values
data, revid_11 = self._storage.load(oid1, '')
assert pickle.loads(data) == 81
assert zodb_unpickle(data) == MinPO(81)
data, revid_22 = self._storage.load(oid2, '')
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
assert revid_11 == revid1 and revid_22 == revid2
# Now modify oid2
revid2 = self._dostore(oid2, revid=revid2, data=p92)
revid2 = self._dostore(oid2, revid=revid2, data=MinPO(92))
assert revid1 <> revid2 and revid2 <> revid_22
info = self._storage.undoInfo()
tid = info[1]['id']
......
# Check interactions between transactionalUndo() and versions. Any storage
# that supports both transactionalUndo() and versions must pass these tests.
import pickle
from ZODB import POSException
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle
class TransactionalUndoVersionStorage:
def checkUndoInVersion(self):
oid = self._storage.new_oid()
version = 'one'
revid_a = self._dostore(oid, data=91)
revid_b = self._dostore(oid, revid=revid_a, data=92, version=version)
revid_c = self._dostore(oid, revid=revid_b, data=93, version=version)
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)
info=self._storage.undoInfo()
tid=info[0]['id']
self._storage.tpc_begin(self._transaction)
......@@ -23,10 +23,10 @@ class TransactionalUndoVersionStorage:
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert revid == revid_a
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
data, revid = self._storage.load(oid, version)
assert revid > revid_b and revid > revid_c
assert pickle.loads(data) == 92
assert zodb_unpickle(data) == MinPO(92)
# Now commit the version...
self._storage.tpc_begin(self._transaction)
oids = self._storage.commitVersion(version, '', self._transaction)
......@@ -40,9 +40,9 @@ class TransactionalUndoVersionStorage:
#JF# self._storage.load,
#JF# oid, version)
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 92
assert zodb_unpickle(data) == MinPO(92)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 92
assert zodb_unpickle(data) == MinPO(92)
# ...and undo the commit
info=self._storage.undoInfo()
tid=info[0]['id']
......@@ -53,9 +53,9 @@ class TransactionalUndoVersionStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 92
assert zodb_unpickle(data) == MinPO(92)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
# Now abort the version
self._storage.tpc_begin(self._transaction)
oids = self._storage.abortVersion(version, self._transaction)
......@@ -70,9 +70,9 @@ class TransactionalUndoVersionStorage:
#JF# self._storage.load,
#JF# oid, version)
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
# Now undo the abort
info=self._storage.undoInfo()
tid=info[0]['id']
......@@ -84,6 +84,6 @@ class TransactionalUndoVersionStorage:
assert oids[0] == oid
# And the object should be back in versions 'one' and ''
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 92
assert zodb_unpickle(data) == MinPO(92)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 91
assert zodb_unpickle(data) == MinPO(91)
# Run the version related tests for a storage. Any storage that supports
# versions should be able to pass all these tests.
try:
import cPickle
pickle = cPickle
#import cPickle as pickle
except ImportError:
import pickle
from ZODB import POSException
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle
class VersionStorage:
def checkVersionedStoreAndLoad(self):
# Store a couple of non-version revisions of the object
oid = self._storage.new_oid()
revid = self._dostore(oid, data=11)
revid = self._dostore(oid, revid=revid, data=12)
revid = self._dostore(oid, data=MinPO(11))
revid = self._dostore(oid, revid=revid, data=MinPO(12))
# And now store some new revisions in a version
version = 'test-version'
revid = self._dostore(oid, revid=revid, data=13, version=version)
revid = self._dostore(oid, revid=revid, data=14, version=version)
revid = self._dostore(oid, revid=revid, data=15, version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(13),
version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(14),
version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(15),
version=version)
# Now read back the object in both the non-version and version and
# make sure the values jive.
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 12
assert zodb_unpickle(data) == MinPO(12)
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 15
assert zodb_unpickle(data) == MinPO(15)
def checkVersionedLoadErrors(self):
oid = self._storage.new_oid()
version = 'test-version'
revid = self._dostore(oid, data=11)
revid = self._dostore(oid, revid=revid, data=12, version=version)
revid = self._dostore(oid, data=MinPO(11))
revid = self._dostore(oid, revid=revid, data=MinPO(12),
version=version)
# Try to load a bogus oid
self.assertRaises(KeyError,
self._storage.load,
......@@ -45,17 +43,17 @@ class VersionStorage:
#JF# self._storage.load,
#JF# oid, 'bogus')
data, revid = self._storage.load(oid, 'bogus')
assert pickle.loads(data) == 11
assert zodb_unpickle(data) == MinPO(11)
def checkVersionLock(self):
oid = self._storage.new_oid()
revid = self._dostore(oid, data=11)
revid = self._dostore(oid, data=MinPO(11))
version = 'test-version'
revid = self._dostore(oid, revid=revid, data=12, version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(12), version=version)
self.assertRaises(POSException.VersionLockError,
self._dostore,
oid, revid=revid, data=14,
oid, revid=revid, data=MinPO(14),
version='another-version')
def checkVersionEmpty(self):
......@@ -67,10 +65,12 @@ class VersionStorage:
assert self._storage.versionEmpty(version)
# Now store some objects
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, version=version)
revid = self._dostore(oid, revid=revid, data=14, version=version)
revid = self._dostore(oid, data=MinPO(11))
revid = self._dostore(oid, revid=revid, data=MinPO(12))
revid = self._dostore(oid, revid=revid, data=MinPO(13),
version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(14),
version=version)
# The blank version should not be empty
#JF# The empty string is not a valid version. I think that this should
#JF# be an error. Let's punt for now.
......@@ -86,13 +86,16 @@ class VersionStorage:
oid1 = self._storage.new_oid()
oid2 = self._storage.new_oid()
oid3 = self._storage.new_oid()
revid1 = self._dostore(oid1, data=11)
revid2 = self._dostore(oid2, data=12)
revid3 = self._dostore(oid3, data=13)
revid1 = self._dostore(oid1, data=MinPO(11))
revid2 = self._dostore(oid2, data=MinPO(12))
revid3 = self._dostore(oid3, data=MinPO(13))
# Now create some new versions
revid1 = self._dostore(oid1, revid=revid1, data=14, version='one')
revid2 = self._dostore(oid2, revid=revid2, data=15, version='two')
revid3 = self._dostore(oid3, revid=revid3, data=16, version='three')
revid1 = self._dostore(oid1, revid=revid1, data=MinPO(14),
version='one')
revid2 = self._dostore(oid2, revid=revid2, data=MinPO(15),
version='two')
revid3 = self._dostore(oid3, revid=revid3, data=MinPO(16),
version='three')
# Ask for the versions
versions = self._storage.versions()
assert 'one' in versions
......@@ -106,13 +109,16 @@ class VersionStorage:
def _setup_version(self, version='test-version'):
# Store some revisions in the non-version
oid = self._storage.new_oid()
revid = self._dostore(oid, data=49)
revid = self._dostore(oid, revid=revid, data=50)
nvrevid = revid = self._dostore(oid, revid=revid, data=51)
revid = self._dostore(oid, data=MinPO(49))
revid = self._dostore(oid, revid=revid, data=MinPO(50))
nvrevid = revid = self._dostore(oid, revid=revid, data=MinPO(51))
# Now do some stores in a version
revid = self._dostore(oid, revid=revid, data=52, version=version)
revid = self._dostore(oid, revid=revid, data=53, version=version)
revid = self._dostore(oid, revid=revid, data=54, version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(52),
version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(53),
version=version)
revid = self._dostore(oid, revid=revid, data=MinPO(54),
version=version)
return oid, version
def checkAbortVersion(self):
......@@ -125,7 +131,7 @@ class VersionStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
def checkAbortVersionErrors(self):
oid, version = self._setup_version()
......@@ -150,7 +156,7 @@ class VersionStorage:
assert len(oids) == 1
assert oids[0] == oid
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
def checkModifyAfterAbortVersion(self):
oid, version = self._setup_version()
......@@ -162,41 +168,41 @@ class VersionStorage:
# Load the object's current state (which gets us the revid)
data, revid = self._storage.load(oid, '')
# And modify it a few times
revid = self._dostore(oid, revid=revid, data=52)
revid = self._dostore(oid, revid=revid, data=53)
revid = self._dostore(oid, revid=revid, data=54)
revid = self._dostore(oid, revid=revid, data=MinPO(52))
revid = self._dostore(oid, revid=revid, data=MinPO(53))
revid = self._dostore(oid, revid=revid, data=MinPO(54))
data, newrevid = self._storage.load(oid, '')
assert newrevid == revid
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
def checkCommitToNonVersion(self):
oid, version = self._setup_version()
data, revid = self._storage.load(oid, version)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 51
assert 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)
data, revid = self._storage.load(oid, '')
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
def checkCommitToOtherVersion(self):
oid1, version1 = self._setup_version('one')
data, revid1 = self._storage.load(oid1, version1)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
oid2, version2 = self._setup_version('two')
data, revid2 = self._storage.load(oid2, version2)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
# Let's make sure we can't get object1 in version2
#JF# This won't fail because we fall back to non-version data.
#JF# In fact, it must succed and give us 51
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version2)
data, revid2 = self._storage.load(oid1, version2)
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
# Okay, now let's commit object1 to version2
self._storage.tpc_begin(self._transaction)
......@@ -207,22 +213,22 @@ class VersionStorage:
assert len(oids) == 1
assert oids[0] == oid1
data, revid = self._storage.load(oid1, version2)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
data, revid = self._storage.load(oid2, version2)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
#JF# Ditto, sort of
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version1)
data, revid2 = self._storage.load(oid1, version1)
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
def checkAbortOneVersionCommitTheOther(self):
oid1, version1 = self._setup_version('one')
data, revid1 = self._storage.load(oid1, version1)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
oid2, version2 = self._setup_version('two')
data, revid2 = self._storage.load(oid2, version2)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
# Let's make sure we can't get object1 in version2
#JF# It's not an error to load data in a different version when data
......@@ -231,7 +237,7 @@ class VersionStorage:
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version2)
data, revid2 = self._storage.load(oid1, version2)
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
# First, let's abort version1
self._storage.tpc_begin(self._transaction)
......@@ -241,22 +247,22 @@ class VersionStorage:
assert len(oids) == 1
assert oids[0] == oid1
data, revid = self._storage.load(oid1, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
#JF# Ditto
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version1)
data, revid = self._storage.load(oid1, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version2)
data, revid = self._storage.load(oid1, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
data, revid = self._storage.load(oid2, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
data, revid = self._storage.load(oid2, version2)
assert pickle.loads(data) == 54
assert 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)
......@@ -269,18 +275,18 @@ class VersionStorage:
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid1, version2)
data, revid = self._storage.load(oid1, '')
assert pickle.loads(data) == 51
assert zodb_unpickle(data) == MinPO(51)
#JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.load, oid2, version2)
# But the trunk should be up to date now
data, revid = self._storage.load(oid2, version2)
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
data, revid = self._storage.load(oid2, '')
assert pickle.loads(data) == 54
assert zodb_unpickle(data) == MinPO(54)
#JF# To do a test like you want, you have to add the data in a version
oid = self._storage.new_oid()
revid = self._dostore(oid, revid=revid, data=54, version='one')
revid = self._dostore(oid, revid=revid, data=MinPO(54), version='one')
self.assertRaises(KeyError,
self._storage.load, oid, '')
self.assertRaises(KeyError,
......
......@@ -7,6 +7,7 @@ import StorageTestBase, BasicStorage, TransactionalUndoStorage
import VersionStorage, TransactionalUndoVersionStorage
import PackableStorage
import Synchronization
import ConflictResolution
class FileStorageTests(
StorageTestBase.StorageTestBase,
......@@ -16,6 +17,7 @@ class FileStorageTests(
TransactionalUndoVersionStorage.TransactionalUndoVersionStorage,
PackableStorage.PackableStorage,
Synchronization.SynchronizedStorage,
ConflictResolution.ConflictResolvingStorage,
):
def setUp(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment