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_poll_lock_exception(tmpdir, monkeypatch, err_num, err_msg): """Test poll lock exception handling.""" def _lockf(fd, cmd, len, start, whence): raise IOError(err_num, err_msg) with tmpdir.as_cwd(): lockfile = 'lockfile' lock = lk.Lock(lockfile) touch(lockfile) monkeypatch.setattr(fcntl, 'lockf', _lockf) if err_num in [errno.EAGAIN, errno.EACCES]: assert not lock._poll_lock(fcntl.LOCK_EX) else: with pytest.raises(IOError, match=err_msg): lock._poll_lock(fcntl.LOCK_EX)
def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path): """Test that read-only file can be read-locked but not write-locked.""" # ensure lock file exists the first time touch(private_lock_path) # open it read-only to begin wtih. with read_only(private_lock_path): lock = lk.Lock(private_lock_path) assert lock._reads == 0 assert lock._writes == 0 lock.acquire_read() assert lock._reads == 1 assert lock._writes == 0 assert lock._file.mode == 'r' # upgrade to writ here with pytest.raises(lk.LockROFileError): lock.acquire_write()
def p1(barrier): lock = lk.Lock(lock_path) lock.acquire_write() barrier.wait() # ---------------------------------------- 1 # others test timeout barrier.wait() # ---------------------------------------- 2 lock.release_write() # release and others acquire read barrier.wait() # ---------------------------------------- 3 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) lock.acquire_read() barrier.wait() # ---------------------------------------- 4 lock.release_read() barrier.wait() # ---------------------------------------- 5 # p2 upgrades read to write barrier.wait() # ---------------------------------------- 6 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 7 # p2 releases write and read barrier.wait() # ---------------------------------------- 8 # p3 acquires read barrier.wait() # ---------------------------------------- 9 # p3 upgrades read to write barrier.wait() # ---------------------------------------- 10 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 11 # p3 releases locks barrier.wait() # ---------------------------------------- 12 lock.acquire_read() barrier.wait() # ---------------------------------------- 13 lock.release_read()
def p3(barrier): lock = lk.Lock(lock_path) # p1 acquires write barrier.wait() # ---------------------------------------- 1 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 2 lock.acquire_read() barrier.wait() # ---------------------------------------- 3 # p1 tests shared read barrier.wait() # ---------------------------------------- 4 lock.release_read() barrier.wait() # ---------------------------------------- 5 # p2 upgrades read to write barrier.wait() # ---------------------------------------- 6 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 7 # p2 releases write & read barrier.wait() # ---------------------------------------- 8 lock.acquire_read() barrier.wait() # ---------------------------------------- 9 lock.acquire_write() barrier.wait() # ---------------------------------------- 10 # others test timeout barrier.wait() # ---------------------------------------- 11 lock.release_read() # release read AND write in opposite lock.release_write() # order from before on p2 barrier.wait() # ---------------------------------------- 12 lock.acquire_read() barrier.wait() # ---------------------------------------- 13 lock.release_read()
def p2(barrier): lock = lk.Lock(lock_path) # p1 acquires write barrier.wait() # ---------------------------------------- 1 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 2 lock.acquire_read() barrier.wait() # ---------------------------------------- 3 # p1 tests shared read barrier.wait() # ---------------------------------------- 4 # others release reads barrier.wait() # ---------------------------------------- 5 lock.acquire_write() # upgrade read to write barrier.wait() # ---------------------------------------- 6 # others test timeout barrier.wait() # ---------------------------------------- 7 lock.release_write() # release read AND write (need both) lock.release_read() barrier.wait() # ---------------------------------------- 8 # p3 acquires read barrier.wait() # ---------------------------------------- 9 # p3 upgrades read to write barrier.wait() # ---------------------------------------- 10 with pytest.raises(lk.LockTimeoutError): lock.acquire_write(lock_fail_timeout) with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait() # ---------------------------------------- 11 # p3 releases locks barrier.wait() # ---------------------------------------- 12 lock.acquire_read() barrier.wait() # ---------------------------------------- 13 lock.release_read()
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 fn(barrier): lock = lk.Lock(lock_path, start, length) barrier.wait() # wait for lock acquire in first process with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait()
def fn(barrier): lock = lk.Lock(lock_path, start, length) lock.acquire_read() # grab shared lock barrier.wait() barrier.wait() # hold the lock until timeout in other procs.
def test_lock_with_no_parent_directory(tmpdir): """Make sure locks work even when their parent directory does not exist.""" with tmpdir.as_cwd(): lock = lk.Lock('foo/bar/baz/lockfile') with lk.WriteTransaction(lock): pass
def __call__(self, barrier): lock = lk.Lock(self.lock_path, self.start, self.length) barrier.wait() # wait for lock acquire in first process with pytest.raises(lk.LockTimeoutError): lock.acquire_read(lock_fail_timeout) barrier.wait()
def __call__(self, barrier): lock = lk.Lock(self.lock_path, self.start, self.length) lock.acquire_read() # grab shared lock barrier.wait() barrier.wait() # hold the lock until timeout in other procs.
def __call__(self, barrier): lock = lk.Lock(self.lock_path, self.start, self.length) lock.acquire_write() # grab exclusive lock barrier.wait() barrier.wait() # hold the lock until timeout in other procs.
def test_lock_str(): lock = lk.Lock('lockfile') lockstr = str(lock) assert 'lockfile[0:0]' in lockstr assert 'timeout=None' in lockstr assert '#reads=0, #writes=0' in lockstr
def fn(barrier): lock = lk.Lock(lock_path, start, length) lock.acquire_write() # grab exclusive lock barrier.wait() barrier.wait() # hold the lock until timeout in other procs.
def test_transaction_with_context_manager_and_exception(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) def do_read_with_exception(exit_fn): with lk.ReadTransaction(lock, TestContextManager, exit_fn): raise Exception() def do_write_with_exception(exit_fn): with lk.WriteTransaction(lock, TestContextManager, exit_fn): raise Exception() vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with pytest.raises(Exception): do_read_with_exception(exit_fn) assert vals['entered'] assert vals['exited'] assert vals['exception'] assert vals['exited_fn'] assert vals['exception_fn'] vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with pytest.raises(Exception): do_read_with_exception(None) assert vals['entered'] assert vals['exited'] assert 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 pytest.raises(Exception): do_write_with_exception(exit_fn) assert vals['entered'] assert vals['exited'] assert vals['exception'] assert vals['exited_fn'] assert vals['exception_fn'] vals = {'entered': False, 'exited': False, 'exited_fn': False, 'exception': False, 'exception_fn': False} with pytest.raises(Exception): do_write_with_exception(None) assert vals['entered'] assert vals['exited'] assert vals['exception'] assert not vals['exited_fn'] assert not vals['exception_fn']
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']