def test_transaction_with_context_manager(lock_path): class TestContextManager(object): def __enter__(self): vals['entered'] = True def __exit__(self, t, v, tb): vals['exited'] = True vals['exception'] = (t or v or tb) def exit_fn(t, v, tb): vals['exited_fn'] = True vals['exception_fn'] = (t or v or tb) lock = lk.Lock(lock_path) vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with lk.ReadTransaction(lock, TestContextManager, exit_fn): pass assert vals['entered'] assert vals['exited'] assert not vals['exception'] assert vals['exited_fn'] assert not vals['exception_fn'] vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with lk.ReadTransaction(lock, TestContextManager): pass assert vals['entered'] assert vals['exited'] assert not vals['exception'] assert not vals['exited_fn'] assert not vals['exception_fn'] vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with lk.WriteTransaction(lock, TestContextManager, exit_fn): pass assert vals['entered'] assert vals['exited'] assert not vals['exception'] assert vals['exited_fn'] assert not vals['exception_fn'] vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with lk.WriteTransaction(lock, TestContextManager): pass assert vals['entered'] assert vals['exited'] assert not vals['exception'] assert not vals['exited_fn'] assert not vals['exception_fn']
def test_nested_write_transaction(lock_path): """Ensure that the outermost write transaction writes.""" def write(t, v, tb): vals['wrote'] = True vals = collections.defaultdict(lambda: False) lock = AssertLock(lock_path, vals) # write/write with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] assert not vals['wrote'] assert vals['wrote'] # read/write vals.clear() with lk.ReadTransaction(lock): assert not vals['wrote'] with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] assert vals['wrote'] # write/read/write vals.clear() with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] with lk.ReadTransaction(lock): assert not vals['wrote'] with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] assert not vals['wrote'] assert not vals['wrote'] assert vals['wrote'] # read/write/read/write vals.clear() with lk.ReadTransaction(lock): with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] with lk.ReadTransaction(lock): assert not vals['wrote'] with lk.WriteTransaction(lock, release=write): assert not vals['wrote'] assert not vals['wrote'] assert not vals['wrote'] assert vals['wrote']
def p1(barrier, q1, q2): # exchange pids p1_pid = os.getpid() q1.put(p1_pid) p2_pid = q2.get() # set up lock lock = lk.Lock(lock_path, debug=True) with lk.WriteTransaction(lock): # p1 takes write lock and writes pid/host to file barrier.wait() # ------------------------------------ 1 assert lock.pid == p1_pid assert lock.host == host # wait for p2 to verify contents of file barrier.wait() # ---------------------------------------- 2 # wait for p2 to take a write lock barrier.wait() # ---------------------------------------- 3 # verify pid/host info again with lk.ReadTransaction(lock): assert lock.old_pid == p1_pid assert lock.old_host == host assert lock.pid == p2_pid assert lock.host == host barrier.wait() # ---------------------------------------- 4
def p2(barrier, q1, q2): # exchange pids p2_pid = os.getpid() p1_pid = q1.get() q2.put(p2_pid) # set up lock lock = lk.Lock(lock_path, debug=True) # p1 takes write lock and writes pid/host to file barrier.wait() # ---------------------------------------- 1 # verify that p1 wrote information to lock file with lk.ReadTransaction(lock): assert lock.pid == p1_pid assert lock.host == host barrier.wait() # ---------------------------------------- 2 # take a write lock on the file and verify pid/host info with lk.WriteTransaction(lock): assert lock.old_pid == p1_pid assert lock.old_host == host assert lock.pid == p2_pid assert lock.host == host barrier.wait() # ------------------------------------ 3 # wait for p1 to verify pid/host info barrier.wait() # ---------------------------------------- 4
def test_lock_in_current_directory(tmpdir): """Make sure locks work even when their parent directory does not exist.""" with tmpdir.as_cwd(): # test we can create a lock in the current directory lock = lk.Lock('lockfile') for i in range(10): with lk.ReadTransaction(lock): pass with lk.WriteTransaction(lock): pass # and that we can do the same thing after it's already there lock = lk.Lock('lockfile') for i in range(10): with lk.ReadTransaction(lock): pass with lk.WriteTransaction(lock): pass
def test_read_lock_read_only_dir_writable_lockfile(lock_dir, lock_path): """read-only directory, writable lockfile.""" touch(lock_path) with read_only(lock_dir): lock = lk.Lock(lock_path) with lk.ReadTransaction(lock): pass with lk.WriteTransaction(lock): pass
def test_read_lock_no_lockfile(lock_dir, lock_path): """read-only directory, no lockfile (so can't create).""" with read_only(lock_dir): lock = lk.Lock(lock_path) with pytest.raises(lk.CantCreateLockError): with lk.ReadTransaction(lock): pass with pytest.raises(lk.CantCreateLockError): with lk.WriteTransaction(lock): pass
def test_read_lock_on_read_only_lockfile(lock_dir, lock_path): """read-only directory, read-only lockfile.""" touch(lock_path) with read_only(lock_path, lock_dir): lock = lk.Lock(lock_path) with lk.ReadTransaction(lock): pass with pytest.raises(lk.LockROFileError): with lk.WriteTransaction(lock): pass
def test_nested_reads(lock_path): """Ensure that write transactions won't re-read data.""" def read(): vals['read'] += 1 vals = collections.defaultdict(lambda: 0) lock = AssertLock(lock_path, vals) # read/read vals.clear() assert vals['read'] == 0 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 # write/write vals.clear() assert vals['read'] == 0 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 # read/write vals.clear() assert vals['read'] == 0 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 # write/read/write vals.clear() assert vals['read'] == 0 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 # read/write/read/write vals.clear() assert vals['read'] == 0 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.ReadTransaction(lock, acquire=read): assert vals['read'] == 1 with lk.WriteTransaction(lock, acquire=read): assert vals['read'] == 1
def test_transaction(lock_path): def enter_fn(): vals['entered'] = True def exit_fn(t, v, tb): vals['exited'] = True vals['exception'] = (t or v or tb) lock = lk.Lock(lock_path) vals = {'entered': False, 'exited': False, 'exception': False} with lk.ReadTransaction(lock, enter_fn, exit_fn): pass assert vals['entered'] assert vals['exited'] assert not vals['exception'] vals = {'entered': False, 'exited': False, 'exception': False} with lk.WriteTransaction(lock, enter_fn, exit_fn): pass assert vals['entered'] assert vals['exited'] assert not vals['exception']
def do_read_with_exception(exit_fn): with lk.ReadTransaction(lock, TestContextManager, exit_fn): raise Exception()
def do_read_with_exception(): with lk.ReadTransaction(lock, enter_fn, exit_fn): raise Exception()