Commit a08c4728 authored by Jim Fulton's avatar Jim Fulton Committed by GitHub

Merge pull request #141 from zopefoundation/issue-138

TransactionUndoStorage tests close the conn and db
parents a97ca02f d4d74383
...@@ -3,7 +3,7 @@ sudo: false ...@@ -3,7 +3,7 @@ sudo: false
matrix: matrix:
include: include:
- os: linux - os: linux
python: pypy python: pypy-5.4.1
- os: linux - os: linux
python: pypy3 python: pypy3
env: BUILOUT_OPTIONS=sphinx:eggs= env: BUILOUT_OPTIONS=sphinx:eggs=
......
...@@ -407,154 +407,167 @@ class TransactionalUndoStorage: ...@@ -407,154 +407,167 @@ class TransactionalUndoStorage:
eq = self.assertEqual eq = self.assertEqual
db = DB(self._storage) db = DB(self._storage)
conn = db.open() conn = db.open()
root = conn.root() try:
root = conn.root()
o1 = C()
o2 = C()
root['obj'] = o1
o1.obj = o2
txn = transaction.get()
txn.note(u'o1 -> o2')
txn.commit()
now = packtime = time.time()
while packtime <= now:
packtime = time.time()
o3 = C()
o2.obj = o3
txn = transaction.get()
txn.note(u'o1 -> o2 -> o3')
txn.commit()
o1.obj = o3
txn = transaction.get()
txn.note(u'o1 -> o3')
txn.commit()
log = self._storage.undoLog()
eq(len(log), 4)
for entry in zip(log, (b'o1 -> o3', b'o1 -> o2 -> o3',
b'o1 -> o2', b'initial database creation')):
eq(entry[0]['description'], entry[1])
self._storage.pack(packtime, referencesf) o1 = C()
o2 = C()
log = self._storage.undoLog() root['obj'] = o1
for entry in zip(log, (b'o1 -> o3', b'o1 -> o2 -> o3')): o1.obj = o2
eq(entry[0]['description'], entry[1]) txn = transaction.get()
txn.note(u'o1 -> o2')
txn.commit()
now = packtime = time.time()
while packtime <= now:
packtime = time.time()
tid = log[0]['id'] o3 = C()
db.undo(tid) o2.obj = o3
txn = transaction.get() txn = transaction.get()
txn.note(u'undo') txn.note(u'o1 -> o2 -> o3')
txn.commit() txn.commit()
# undo does a txn-undo, but doesn't invalidate
conn.sync()
log = self._storage.undoLog() o1.obj = o3
for entry in zip(log, (b'undo', b'o1 -> o3', b'o1 -> o2 -> o3')): txn = transaction.get()
eq(entry[0]['description'], entry[1]) txn.note(u'o1 -> o3')
txn.commit()
eq(o1.obj, o2) log = self._storage.undoLog()
eq(o1.obj.obj, o3) eq(len(log), 4)
self._iterate() for entry in zip(log, (b'o1 -> o3', b'o1 -> o2 -> o3',
b'o1 -> o2', b'initial database creation')):
eq(entry[0]['description'], entry[1])
def checkPackAfterUndoDeletion(self): self._storage.pack(packtime, referencesf)
db = DB(self._storage)
cn = db.open()
root = cn.root()
pack_times = [] log = self._storage.undoLog()
def set_pack_time(): for entry in zip(log, (b'o1 -> o3', b'o1 -> o2 -> o3')):
pack_times.append(time.time()) eq(entry[0]['description'], entry[1])
snooze()
root["key0"] = MinPO(0) tid = log[0]['id']
root["key1"] = MinPO(1) db.undo(tid)
root["key2"] = MinPO(2) txn = transaction.get()
txn = transaction.get() txn.note(u'undo')
txn.note(u"create 3 keys") txn.commit()
txn.commit() # undo does a txn-undo, but doesn't invalidate
conn.sync()
set_pack_time() log = self._storage.undoLog()
for entry in zip(log, (b'undo', b'o1 -> o3', b'o1 -> o2 -> o3')):
eq(entry[0]['description'], entry[1])
del root["key1"] eq(o1.obj, o2)
txn = transaction.get() eq(o1.obj.obj, o3)
txn.note(u"delete 1 key") self._iterate()
txn.commit() finally:
conn.close()
db.close()
set_pack_time() def checkPackAfterUndoDeletion(self):
db = DB(self._storage)
cn = db.open()
try:
root = cn.root()
root._p_deactivate() pack_times = []
cn.sync() def set_pack_time():
self.assertTrue(listeq(root.keys(), ["key0", "key2"])) pack_times.append(time.time())
snooze()
L = db.undoInfo() root["key0"] = MinPO(0)
db.undo(L[0]["id"]) root["key1"] = MinPO(1)
txn = transaction.get() root["key2"] = MinPO(2)
txn.note(u"undo deletion") txn = transaction.get()
txn.commit() txn.note(u"create 3 keys")
txn.commit()
set_pack_time() set_pack_time()
root._p_deactivate() del root["key1"]
cn.sync() txn = transaction.get()
self.assertTrue(listeq(root.keys(), ["key0", "key1", "key2"])) txn.note(u"delete 1 key")
txn.commit()
for t in pack_times: set_pack_time()
self._storage.pack(t, referencesf)
root._p_deactivate() root._p_deactivate()
cn.sync() cn.sync()
self.assertTrue(listeq(root.keys(), ["key0", "key1", "key2"])) self.assertTrue(listeq(root.keys(), ["key0", "key2"]))
for i in range(3):
obj = root["key%d" % i]
self.assertEqual(obj.value, i)
root.items()
self._inter_pack_pause()
def checkPackAfterUndoManyTimes(self):
db = DB(self._storage)
cn = db.open()
rt = cn.root()
rt["test"] = MinPO(1)
transaction.commit()
rt["test2"] = MinPO(2)
transaction.commit()
rt["test"] = MinPO(3)
txn = transaction.get()
txn.note(u"root of undo")
txn.commit()
packtimes = []
for i in range(10):
L = db.undoInfo() L = db.undoInfo()
db.undo(L[0]["id"]) db.undo(L[0]["id"])
txn = transaction.get() txn = transaction.get()
txn.note(u"undo %d" % i) txn.note(u"undo deletion")
txn.commit() txn.commit()
rt._p_deactivate()
set_pack_time()
root._p_deactivate()
cn.sync() cn.sync()
self.assertTrue(listeq(root.keys(), ["key0", "key1", "key2"]))
self.assertEqual(rt["test"].value, i % 2 and 3 or 1) for t in pack_times:
self.assertEqual(rt["test2"].value, 2) self._storage.pack(t, referencesf)
packtimes.append(time.time()) root._p_deactivate()
snooze() cn.sync()
self.assertTrue(listeq(root.keys(), ["key0", "key1", "key2"]))
for i in range(3):
obj = root["key%d" % i]
self.assertEqual(obj.value, i)
root.items()
self._inter_pack_pause()
finally:
cn.close()
db.close()
for t in packtimes:
self._storage.pack(t, referencesf)
cn.sync()
# TODO: Is _cache supposed to have a clear() method, or not? def checkPackAfterUndoManyTimes(self):
# cn._cache.clear() db = DB(self._storage)
cn = db.open()
try:
rt = cn.root()
# The last undo set the value to 3 and pack should rt["test"] = MinPO(1)
# never change that. transaction.commit()
self.assertEqual(rt["test"].value, 3) rt["test2"] = MinPO(2)
self.assertEqual(rt["test2"].value, 2) transaction.commit()
self._inter_pack_pause() rt["test"] = MinPO(3)
txn = transaction.get()
txn.note(u"root of undo")
txn.commit()
packtimes = []
for i in range(10):
L = db.undoInfo()
db.undo(L[0]["id"])
txn = transaction.get()
txn.note(u"undo %d" % i)
txn.commit()
rt._p_deactivate()
cn.sync()
self.assertEqual(rt["test"].value, i % 2 and 3 or 1)
self.assertEqual(rt["test2"].value, 2)
packtimes.append(time.time())
snooze()
for t in packtimes:
self._storage.pack(t, referencesf)
cn.sync()
# TODO: Is _cache supposed to have a clear() method, or not?
# cn._cache.clear()
# The last undo set the value to 3 and pack should
# never change that.
self.assertEqual(rt["test"].value, 3)
self.assertEqual(rt["test2"].value, 2)
self._inter_pack_pause()
finally:
cn.close()
db.close()
def _inter_pack_pause(self): def _inter_pack_pause(self):
# DirectoryStorage needs a pause between packs, # DirectoryStorage needs a pause between packs,
...@@ -654,17 +667,21 @@ class TransactionalUndoStorage: ...@@ -654,17 +667,21 @@ class TransactionalUndoStorage:
t.setUser(u'u3',path=u'p3') t.setUser(u'u3',path=u'p3')
db = DB(self._storage) db = DB(self._storage)
conn = db.open() conn = db.open()
root = conn.root() try:
o1 = C() root = conn.root()
root['obj'] = o1 o1 = C()
txn = transaction.get() root['obj'] = o1
txn.commit() txn = transaction.get()
l = self._storage.undoLog() txn.commit()
self.assertEqual(len(l),2) l = self._storage.undoLog()
d = l[0] self.assertEqual(len(l),2)
self.assertEqual(d['description'], b't1') d = l[0]
self.assertEqual(d['k2'], 'this is transaction metadata') self.assertEqual(d['description'], b't1')
self.assertEqual(d['user_name'], b'p3 u3') self.assertEqual(d['k2'], 'this is transaction metadata')
self.assertEqual(d['user_name'], b'p3 u3')
finally:
conn.close()
db.close()
# A common test body for index tests on undoInfo and undoLog. Before # A common test body for index tests on undoInfo and undoLog. Before
# ZODB 3.4, they always returned a wrong number of results (one too # ZODB 3.4, they always returned a wrong number of results (one too
...@@ -729,26 +746,28 @@ class TransactionalUndoStorage: ...@@ -729,26 +746,28 @@ class TransactionalUndoStorage:
def checkUndoMultipleConflictResolution(self, reverse=False): def checkUndoMultipleConflictResolution(self, reverse=False):
from .ConflictResolution import PCounter from .ConflictResolution import PCounter
db = DB(self._storage) db = DB(self._storage)
cn = db.open() cn = db.open()
cn.root.x = PCounter() try:
transaction.commit() cn.root.x = PCounter()
transaction.commit()
for i in range(4): for i in range(4):
with db.transaction() as conn: with db.transaction() as conn:
conn.transaction_manager.get().note( conn.transaction_manager.get().note(
(str if PY3 else unicode)(i)) (str if PY3 else unicode)(i))
conn.root.x.inc() conn.root.x.inc()
ids = [l['id'] for l in db.undoLog(1, 3)] ids = [l['id'] for l in db.undoLog(1, 3)]
if reverse: if reverse:
ids.reverse() ids.reverse()
db.undoMultiple(ids) db.undoMultiple(ids)
transaction.commit() transaction.commit()
self.assertEqual(cn.root.x._value, 2) self.assertEqual(cn.root.x._value, 2)
cn.close() finally:
cn.close()
db.close()
def checkUndoMultipleConflictResolutionReversed(self): def checkUndoMultipleConflictResolutionReversed(self):
self.checkUndoMultipleConflictResolution(True) self.checkUndoMultipleConflictResolution(True)
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