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