Commit d8a8c0fc authored by Joshua Woelfel's avatar Joshua Woelfel

Updated test_multi_commit and increaseByOne to properly verify whether...

Updated test_multi_commit and increaseByOne to properly verify whether connections viewed db state is correct, and changed usage of two objects to just a single object during tests
parent 53f912a8
...@@ -10,7 +10,7 @@ from ZODB.POSException import ConflictError ...@@ -10,7 +10,7 @@ from ZODB.POSException import ConflictError
from golang import func, defer, chan, select, default from golang import func, defer, chan, select, default
from golang import sync, context from golang import sync, context
from random import randint import threading
import threading import threading
CONNECTED = 1 CONNECTED = 1
...@@ -20,9 +20,7 @@ THREAD2 = 1 ...@@ -20,9 +20,7 @@ THREAD2 = 1
START = 0 START = 0
END = 1 END = 1
TID = 0 TID = 0
OBJ1_VAL = 0 OBJ1_VAL = 1
OBJ2_VAL = 1
OBJECTS = 1
TRANSACTION_CONFLICT = None TRANSACTION_CONFLICT = None
# PInt is persistent integer. # PInt is persistent integer.
class PInt(Persistent): class PInt(Persistent):
...@@ -31,13 +29,13 @@ class PInt(Persistent): ...@@ -31,13 +29,13 @@ class PInt(Persistent):
class Zconn_atTest(unittest.TestCase): class Zconn_atTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.lock = threading.Lock()
self.db = DB(MappingStorage()) self.db = DB(MappingStorage())
transaction.begin() transaction.begin()
connection = self.db.open() connection = self.db.open()
root = connection.root() root = connection.root()
root['obj1'] = PInt(0) root['obj1'] = PInt(0)
root['obj2'] = PInt(0)
transaction.commit() transaction.commit()
connection.close() connection.close()
...@@ -48,9 +46,7 @@ class Zconn_atTest(unittest.TestCase): ...@@ -48,9 +46,7 @@ class Zconn_atTest(unittest.TestCase):
root = connection.root() root = connection.root()
obj1 = root['obj1'] obj1 = root['obj1']
obj2 = root['obj2']
obj1.i += 1 obj1.i += 1
obj2.i += 1
try: try:
transaction.commit() transaction.commit()
...@@ -76,9 +72,7 @@ class Zconn_atTest(unittest.TestCase): ...@@ -76,9 +72,7 @@ class Zconn_atTest(unittest.TestCase):
connection = self.db.open() connection = self.db.open()
obj1 = connection.root()['obj1'] obj1 = connection.root()['obj1']
obj2 = connection.root()['obj2']
obj1.i += 1 obj1.i += 1
obj2.i += 1
tid_before_commit = u64(zconn_at(connection)) tid_before_commit = u64(zconn_at(connection))
transaction.commit() transaction.commit()
...@@ -93,9 +87,7 @@ class Zconn_atTest(unittest.TestCase): ...@@ -93,9 +87,7 @@ class Zconn_atTest(unittest.TestCase):
connection = self.db.open(None, p64(tid_after_commit)) connection = self.db.open(None, p64(tid_after_commit))
obj1 = connection.root()['obj1'] obj1 = connection.root()['obj1']
obj2 = connection.root()['obj2'] self.assertEqual(obj1.i, 1, 'db returns unexpected obj1 at tid')
self.assertEqual(obj1.i, 1, 'db returns unexpected obj1 at tid')
self.assertEqual(obj2.i, 1, 'db returns unexpected obj2 at tid')
# check that different connections at same db state report the same # check that different connections at same db state report the same
# db state tid # db state tid
...@@ -119,8 +111,6 @@ class Zconn_atTest(unittest.TestCase): ...@@ -119,8 +111,6 @@ class Zconn_atTest(unittest.TestCase):
transaction.abort() transaction.abort()
connection.close() connection.close()
raise error raise error
#transaction.abort()
#connection.close()
def T2(ctx, self): def T2(ctx, self):
T1_is_connected.recv() T1_is_connected.recv()
...@@ -244,12 +234,8 @@ class Zconn_atTest(unittest.TestCase): ...@@ -244,12 +234,8 @@ class Zconn_atTest(unittest.TestCase):
compareRecordedStates(self, correct_states, actual_states) compareRecordedStates(self, correct_states, actual_states)
# Check for concurrency issues with simultaneous commits. # Check for possible concurrency issues with connection state following
# On the assumption that following a transaction by connection A (and not # transaction, when multiple threads make changes to db.
# the connection) zconn_at(A) should then return the tid of the db state with changes
# just made by A but not any following changes afterwards by other connections,
# it currently fails as the db state tid following successful transaction
# is not unique.
@func @func
def test_multi_commit(self): def test_multi_commit(self):
correct_states = {} correct_states = {}
...@@ -260,9 +246,7 @@ class Zconn_atTest(unittest.TestCase): ...@@ -260,9 +246,7 @@ class Zconn_atTest(unittest.TestCase):
if ready(ctx.done()): if ready(ctx.done()):
break break
else: else:
new_state = increaseByOne(self, correct_states) increaseByOne(self, correct_states)
if not(new_state == TRANSACTION_CONFLICT):
validateState(self, correct_states, new_state)
wg = sync.WorkGroup(context.background()) wg = sync.WorkGroup(context.background())
wg.go(T, self) wg.go(T, self)
...@@ -276,18 +260,15 @@ def compareRecordedStates(test, correct_states, actual_states): ...@@ -276,18 +260,15 @@ def compareRecordedStates(test, correct_states, actual_states):
for state in actual_states: for state in actual_states:
actual_tid = state[TID] actual_tid = state[TID]
if not(actual_tid in correct_states):
print("wtf")
test.assertIn(actual_tid, correct_states, 'tid (%d) should not exist' % actual_tid) test.assertIn(actual_tid, correct_states, 'tid (%d) should not exist' % actual_tid)
actual_obj1_val = state[OBJECTS][OBJ1_VAL] actual_obj1_val = state[OBJ1_VAL]
actual_obj2_val = state[OBJECTS][OBJ2_VAL] expected_obj1_val = correct_states[actual_tid]
expected_obj1_val = correct_states[actual_tid][OBJ1_VAL]
expected_obj2_val = correct_states[actual_tid][OBJ2_VAL]
test.assertEqual(actual_obj1_val, expected_obj1_val, test.assertEqual(actual_obj1_val, expected_obj1_val,
'at db state (%d) recorded obj1 was (%s), should have been (%s)' 'at db state (%d) recorded obj1 was (%s), should have been (%s)'
% (actual_tid, actual_obj1_val, expected_obj1_val)) % (actual_tid, actual_obj1_val, expected_obj1_val))
test.assertEqual(actual_obj2_val, expected_obj2_val,
'at db state (%d) recorded obj2 was (%s), should have been (%s)'
% (actual_tid, actual_obj2_val, expected_obj2_val))
# Connects with the db and records the tid of the current db state along with # Connects with the db and records the tid of the current db state along with
# the value of obj1 and obj2 in actual_states. If obj1 or obj2 does not exist # the value of obj1 and obj2 in actual_states. If obj1 or obj2 does not exist
...@@ -298,17 +279,14 @@ def recordDbState(test, actual_states): ...@@ -298,17 +279,14 @@ def recordDbState(test, actual_states):
db_state = u64(zconn_at(connection)) db_state = u64(zconn_at(connection))
root = connection.root() root = connection.root()
obj1_val = None obj1_val = None
obj2_val = None
if 'obj1' in root: if 'obj1' in root:
obj1_val = root['obj1'].i obj1_val = root['obj1'].i
if 'obj2' in root:
obj2_val = root['obj2'].i
transaction.abort() transaction.abort()
connection.close() connection.close()
actual_states.append((db_state, (obj1_val, obj2_val))) actual_states.append((db_state, obj1_val))
# If obj1/obj2 exist in db, removes them. Otherwise creates and # If obj1/obj2 exist in db, removes them. Otherwise creates and
# initializes them with value of 0. Then commits changes and stores # initializes them with value of 0. Then commits changes and stores
...@@ -319,22 +297,16 @@ def removeOrAddObj(test, correct_states): ...@@ -319,22 +297,16 @@ def removeOrAddObj(test, correct_states):
connection = test.db.open() connection = test.db.open()
root = connection.root() root = connection.root()
obj1_val = None obj1_val = None
obj2_val = None
if 'obj1' in root: if 'obj1' in root:
del root['obj1'] del root['obj1']
else: else:
root['obj1'] = PInt(0) root['obj1'] = PInt(0)
obj1_val = 0 obj1_val = 0
if 'obj2' in root:
del root['obj2']
else:
root['obj2'] = PInt(0)
obj2_val = 0
try: try:
transaction.commit() transaction.commit()
correct_states[u64(zconn_at(connection))] = (obj1_val, obj2_val) correct_states[u64(zconn_at(connection))] = obj1_val
except ConflictError: except ConflictError:
transaction.abort() transaction.abort()
...@@ -349,63 +321,55 @@ def storeInitTid(test, correct_states): ...@@ -349,63 +321,55 @@ def storeInitTid(test, correct_states):
connection = test.db.open() connection = test.db.open()
root = connection.root() root = connection.root()
obj1_val = root['obj1'].i obj1_val = root['obj1'].i
obj2_val = root['obj2'].i correct_states[u64(test.db.lastTransaction())] = obj1_val
correct_states[u64(test.db.lastTransaction())] = (obj1_val, obj2_val)
transaction.abort() transaction.abort()
connection.close() connection.close()
# Increases values of objects in db, then stores them with the tid # Increases value of PInt object stored in db by one, then attempts to commit
# of the changes made in correct_states # changes to db. If commit was successful, calls validate state to verify
# connections viewed state of db is correct following commit. Then stores tid
# viewed by connection in correct_states along with PInt object value
def increaseByOne(test, correct_states): def increaseByOne(test, correct_states):
transaction.begin() transaction.begin()
connection = test.db.open() connection = test.db.open()
root = connection.root() root = connection.root()
obj1 = root['obj1'] obj1 = root['obj1']
obj2 = root['obj2']
obj1._p_invalidate() obj1._p_invalidate()
obj2._p_invalidate() obj1.i += 1
obj1.i += randint(1, 4) obj1_ooid = obj1._p_oid
obj2.i += randint(1, 4)
obj1_val = obj1.i
obj2_val = obj2.i
try: try:
transaction.commit() transaction.commit()
curr_state = u64(zconn_at(connection)) curr_state = zconn_at(connection)
if curr_state in correct_states: obj1_val = validateState(test, connection, curr_state, obj1_ooid)
connection.close() test.lock.acquire()
rec_obj1 = correct_states[curr_state][OBJ1_VAL] if not(curr_state in correct_states):
rec_obj2 = correct_states[curr_state][OBJ2_VAL] correct_states[u64(curr_state)] = obj1_val
test.fail('db state after successfull transaction is not unique. State: %d already recorded with obj1: %s, obj2: %s. This state: %d, obj1: %s, obj2: %s' test.lock.release()
% (curr_state, rec_obj1, rec_obj2, curr_state, obj1_val, obj2_val))
else:
correct_states[curr_state] = (obj1_val, obj2_val)
except ConflictError: except ConflictError:
transaction.abort() transaction.abort()
curr_state = None
connection.close() connection.close()
return curr_state
# validates that the db state at curr_state has the same values stored in # validates that the db state viewed by connection is representative
# current_states # of c_state, by comparing ooid's object of connection and ooid's object
def validateState(test, current_states, curr_state): # of a newly opened historic connection at c_state
connection = test.db.open(None, p64(curr_state)) def validateState(test, connection, c_state, ooid):
root = connection.root() obj_c = connection.get(ooid)
obj1 = root['obj1'] connection.setstate(obj_c)
obj2 = root['obj2']
obj1._p_invalidate() connection2 = test.db.open(at=c_state)
obj2._p_invalidate() obj_c2 = connection2.get(ooid)
actual_obj1_val = obj1.i connection2.setstate(obj_c2)
actual_obj2_val = obj2.i
expected_obj1_val = current_states[curr_state][OBJ1_VAL] test.assertEqual(obj_c.i, obj_c2.i,
expected_obj2_val = current_states[curr_state][OBJ2_VAL] 'wrong db state reported following transaction.'\
connection.close() 'State (%d): obj1 had value (%s) but according to'\
test.assertEqual(actual_obj1_val, expected_obj1_val, 'historic connection should be (%s)'
'db state (%d) is invalid, obj1 had value (%s) but should be (%s)' % (u64(c_state), obj_c.i, obj_c2.i))
% (curr_state, actual_obj1_val, expected_obj1_val)) connection2.close()
return obj_c.i
def ready(ch): def ready(ch):
_, _rx = select( _, _rx = select(
......
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