Commit 097e74a2 authored by Julien Muchembled's avatar Julien Muchembled

Check invalidation in case of conflict resolution

parent f46359eb
......@@ -13,9 +13,10 @@
##############################################################################
"""Tests for application-level conflict resolution."""
from ZODB import DB
from ZODB.POSException import ConflictError, UndoError
from persistent import Persistent
from transaction import Transaction
from transaction import Transaction, TransactionManager
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
......@@ -26,8 +27,8 @@ class PCounter(Persistent):
def __repr__(self):
return "<PCounter %d>" % self._value
def inc(self):
self._value = self._value + 1
def inc(self, n=1):
self._value = self._value + n
def _p_resolveConflict(self, oldState, savedState, newState):
savedDiff = savedState['_value'] - oldState['_value']
......@@ -55,46 +56,38 @@ class PCounter4(PCounter):
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.assertEqual(inst._value, 5)
def checkUnresolvable(self):
obj = PCounter2()
obj.inc()
def checkResolve(self, resolvable=True):
db = DB(self._storage)
oid = self._storage.new_oid()
t1 = TransactionManager()
c1 = db.open(t1)
o1 = c1.root()['p'] = (PCounter if resolvable else PCounter2)()
o1.inc()
t1.commit()
revid1 = self._dostoreNP(oid, data=zodb_pickle(obj))
t2 = TransactionManager()
c2 = db.open(t2)
o2 = c2.root()['p']
o2.inc(2)
t2.commit()
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))
o1.inc(3)
try:
self._dostoreNP(oid, revid=revid1, data=zodb_pickle(obj))
t1.commit()
except ConflictError as err:
self.assertTrue("PCounter2" in str(err))
self.assertIn(".PCounter2,", str(err))
self.assertEqual(o1._value, 3)
else:
self.fail("Expected ConflictError")
self.assertTrue(resolvable, "Expected ConflictError")
self.assertEqual(o1._value, 6)
t2.begin()
self.assertEqual(o2._value, o1._value)
db.close()
def checkUnresolvable(self):
self.checkResolve(False)
def checkZClassesArentResolved(self):
from ZODB.ConflictResolution import find_global, BadClassName
......
......@@ -39,6 +39,31 @@ import ZODB.tests.util
import ZODB.utils
from zope.testing import renormalizing
# With the following monkey-patch, we can test the different ways
# to update _p_changed/_p_serial status of committed oids.
class DemoStorage(ZODB.DemoStorage.DemoStorage):
delayed_store = False
def tpc_begin(self, *args):
super(DemoStorage, self).tpc_begin(*args)
self.__stored = []
def store(self, oid, *args):
s = super(DemoStorage, self).store(oid, *args)
if not self.delayed_store:
return s
self.__stored.append((oid, s))
tpc_vote = property(lambda self: self._tpc_vote, lambda *_: None)
def _tpc_vote(self, transaction):
s = self.changes.tpc_vote(transaction)
assert s is None, s
return self.__stored if self.delayed_store else s
ZODB.DemoStorage.DemoStorage = DemoStorage
class DemoStorageTests(
StorageTestBase.StorageTestBase,
......@@ -104,6 +129,10 @@ class DemoStorageTests(
self._checkHistory(base_and_changes())
self._storage = self._storage.pop()
def checkResolveLate(self):
self._storage.delayed_store = True
self.checkResolve()
class DemoStorageHexTests(DemoStorageTests):
......
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