def test_reader_recursion(loop): rwlock = RWLock(loop=loop) N = 5 locked = [] nlocked = [] @asyncio.coroutine def f(): yield from rwlock.reader_lock.acquire() try: yield from rwlock.reader_lock.acquire() try: locked.append(1) yield from _wait(loop=loop) nlocked.append(len(locked)) yield from _wait(loop=loop) locked.pop(-1) finally: rwlock.reader_lock.release() finally: rwlock.reader_lock.release() yield from Bunch(f, N, loop=loop).wait_for_finished() assert max(nlocked) > 1
async def test_writer_success_with_statement(loop): # Verify that a writer can get access rwlock = RWLock() N = 5 reads = 0 writes = 0 async def r(): # read until we achive write successes nonlocal reads, writes while writes < 2: # print("current pre-reads", reads) async with rwlock.reader_lock: reads += 1 # print("current reads", reads) async def w(): nonlocal reads, writes while reads == 0: await _wait() for _ in range(2): await _wait() # print("current pre-writes", reads) async with rwlock.writer_lock: writes += 1 b1 = Bunch(r, N) b2 = Bunch(w, 1) await b1.wait_for_finished() await b2.wait_for_finished() assert writes == 2
def test_get_write_then_read_and_write_again(loop): rwlock = RWLock(loop=loop) rl = rwlock.reader wl = rwlock.writer f = create_future(loop) writes = [] @asyncio.coroutine def get_write_lock(): yield from f with should_fail(.1, loop): with (yield from wl): assert wl.locked writes.append('should not be here') ensure_future(get_write_lock(), loop=loop) with (yield from wl): assert wl.locked with (yield from rl): f.set_result(None) yield from asyncio.sleep(0.12, loop=loop) # second task can not append to writes assert writes == [] assert rl.locked
async def test_writers_deadlock(loop): rwlock = RWLock() rl = rwlock.reader wl = rwlock.writer # Scenario: # - task A (this) acquires read lock # - task B,C wait for write lock # # A releases the lock and, in the same loop interation, # task B gets cancelled (eg: by timeout); # B gets cancelled without waking up next waiter -- deadlock; # # See asyncio.Lock deadlock issue: # https://github.com/python/cpython/pull/1031 async def coro(): async with wl: assert wl.locked await asyncio.sleep(0.2, loop) async with rl: assert rl.locked task_b = ensure_future(coro()) task_c = ensure_future(coro()) await asyncio.sleep(0.1, loop) # cancel lock waiter right after release task_b.cancel() assert not rl.locked # wait task_c to complete await asyncio.sleep(0.3, loop) assert task_c.done() assert not rl.locked assert not wl.locked
async def test_get_write_then_read_and_write_again(loop): rwlock = RWLock() rl = rwlock.reader wl = rwlock.writer f = loop.create_future() writes = [] async def get_write_lock(): await f with should_fail(0.1, loop): async with wl: assert wl.locked writes.append('should not be here') ensure_future(get_write_lock()) async with wl: assert wl.locked async with rl: f.set_result(None) await asyncio.sleep(0.12) # second task can not append to writes assert writes == [] assert rl.locked
async def test_get_write_then_read(loop): rwlock = RWLock() rl = rwlock.reader wl = rwlock.writer async with wl: assert wl.locked assert not rl.locked async with rl: assert wl.locked assert rl.locked
def test_get_write_then_read(loop): rwlock = RWLock(loop=loop) rl = rwlock.reader wl = rwlock.writer with (yield from wl): assert wl.locked assert not rl.locked with (yield from rl): assert wl.locked assert rl.locked
async def test_readers_writers(loop, fast_track): rwlock = RWLock(fast=fast_track) N = 5 rlocked = [] wlocked = [] nlocked = [] async def r(): await rwlock.reader_lock.acquire() try: rlocked.append(1) await _wait() nlocked.append((len(rlocked), len(wlocked))) await _wait() rlocked.pop(-1) finally: rwlock.reader_lock.release() async def w(): await rwlock.writer_lock.acquire() try: wlocked.append(1) await _wait() nlocked.append((len(rlocked), len(wlocked))) await _wait() wlocked.pop(-1) finally: rwlock.writer_lock.release() b1 = Bunch(r, N) b2 = Bunch(w, N) await asyncio.sleep(0.0001) await b1.wait_for_finished() await b2.wait_for_finished() ( r, w, ) = zip(*nlocked) assert max(r) > 1 assert max(w) == 1 for r, w in nlocked: if w: assert r == 0 if r: assert w == 0
def test_readers_writers(loop): rwlock = RWLock(loop=loop) N = 5 rlocked = [] wlocked = [] nlocked = [] @asyncio.coroutine def r(): yield from rwlock.reader_lock.acquire() try: rlocked.append(1) yield from _wait(loop=loop) nlocked.append((len(rlocked), len(wlocked))) yield from _wait(loop=loop) rlocked.pop(-1) finally: rwlock.reader_lock.release() @asyncio.coroutine def w(): yield from rwlock.writer_lock.acquire() try: wlocked.append(1) yield from _wait(loop=loop) nlocked.append((len(rlocked), len(wlocked))) yield from _wait(loop=loop) wlocked.pop(-1) finally: rwlock.writer_lock.release() b1 = Bunch(r, N, loop=loop) b2 = Bunch(w, N, loop=loop) yield from asyncio.sleep(0.0001, loop=loop) yield from b1.wait_for_finished() yield from b2.wait_for_finished() r, w, = zip(*nlocked) assert max(r) > 1 assert max(w) == 1 for r, w in nlocked: if w: assert r == 0 if r: assert w == 0
def test_repr(loop): rwlock = RWLock(loop=loop) assert 'RWLock' in rwlock.__repr__() assert 'WriterLock: [unlocked' in rwlock.__repr__() assert 'ReaderLock: [unlocked' in rwlock.__repr__() # reader lock __repr__ yield from rwlock.reader_lock.acquire() assert 'ReaderLock: [locked]' in rwlock.__repr__() rwlock.reader_lock.release() assert 'ReaderLock: [unlocked]' in rwlock.__repr__() # writer lock __repr__ yield from rwlock.writer_lock.acquire() assert 'WriterLock: [locked]' in rwlock.__repr__() rwlock.writer_lock.release() assert 'WriterLock: [unlocked]' in rwlock.__repr__()
async def test_repr(loop): rwlock = RWLock() assert 'RWLock' in rwlock.__repr__() assert 'WriterLock: [unlocked' in rwlock.__repr__() assert 'ReaderLock: [unlocked' in rwlock.__repr__() # reader lock __repr__ await rwlock.reader_lock.acquire() assert 'ReaderLock: [locked]' in rwlock.__repr__() rwlock.reader_lock.release() assert 'ReaderLock: [unlocked]' in rwlock.__repr__() # writer lock __repr__ await rwlock.writer_lock.acquire() assert 'WriterLock: [locked]' in rwlock.__repr__() rwlock.writer_lock.release() assert 'WriterLock: [unlocked]' in rwlock.__repr__()
async def test_writer_recursion_fail(loop): rwlock = RWLock() N = 5 locked = [] async def f(): await rwlock.reader_lock.acquire() try: with pytest.raises(RuntimeError): await rwlock.writer_lock.acquire() locked.append(1) finally: rwlock.reader_lock.release() await Bunch(f, N).wait_for_finished() assert len(locked) == N
def test_writer_recursion_fail(loop): rwlock = RWLock(loop=loop) N = 5 locked = [] @asyncio.coroutine def f(): yield from rwlock.reader_lock.acquire() try: with pytest.raises(RuntimeError): yield from rwlock.writer_lock.acquire() locked.append(1) finally: rwlock.reader_lock.release() yield from Bunch(f, N, loop=loop).wait_for_finished() assert len(locked) == N
async def test_canceled_inside_acquire(loop): rwlock = RWLock() rl = rwlock.reader async def coro(lock): async with lock: pass task = ensure_future(coro(rl)) await asyncio.sleep(0) task.cancel() try: await task except asyncio.CancelledError: pass assert not rl.locked
def test_writer_success_fast(loop): # Verify that a writer can get access rwlock = RWLock(loop=loop, fast=True) N = 5 reads = 0 writes = 0 @asyncio.coroutine def r(): # read until we achive write successes nonlocal reads, writes while writes < 2: # print("current pre-reads", reads) yield from rwlock.reader_lock.acquire() try: reads += 1 # print("current reads", reads) yield from asyncio.sleep(0, loop=loop) finally: rwlock.reader_lock.release() @asyncio.coroutine def w(): nonlocal reads, writes while reads == 0: yield from _wait(loop=loop) for i in range(2): yield from _wait(loop=loop) # print("current pre-writes", reads) yield from rwlock.writer_lock.acquire() try: writes += 1 # print("current writes", reads) finally: rwlock.writer_lock.release() b1 = Bunch(r, N, loop=loop) b2 = Bunch(w, 1, loop=loop) yield from b1.wait_for_finished() yield from b2.wait_for_finished() assert writes == 2
async def test_repr(loop): rwlock = RWLock(loop=loop) assert 'RWLock' in rwlock.__repr__() assert 'WriterLock: [unlocked' in rwlock.__repr__() assert 'ReaderLock: [unlocked' in rwlock.__repr__() # reader lock __repr__ await rwlock.reader_lock.acquire() assert 'ReaderLock: [locked]' in rwlock.__repr__() rwlock.reader_lock.release() assert 'ReaderLock: [unlocked]' in rwlock.__repr__() # writer lock __repr__ await rwlock.writer_lock.acquire() assert 'WriterLock: [locked]' in rwlock.__repr__() rwlock.writer_lock.release() assert 'WriterLock: [unlocked]' in rwlock.__repr__()
async def test_write_read_lock_multiple_tasks(loop, fast_track): rwlock = RWLock(fast=fast_track) rl = rwlock.reader wl = rwlock.writer async def coro(): async with rl: assert not wl.locked assert rl.locked await asyncio.sleep(0.2, loop) async with wl: assert wl.locked assert not rl.locked task = asyncio.Task(coro()) await asyncio.sleep(0.1, loop) await task assert not rl.locked assert not wl.locked
async def test_many_readers(loop, fast_track): rwlock = RWLock(fast=fast_track) N = 5 locked = [] nlocked = [] async def f(): await rwlock.reader_lock.acquire() try: locked.append(1) await _wait() nlocked.append(len(locked)) await _wait() locked.pop(-1) finally: rwlock.reader_lock.release() await Bunch(f, N).wait_for_finished() assert max(nlocked) > 1
async def test_writer_success_fast(loop): # Verify that a writer can get access rwlock = RWLock(fast=True) N = 5 reads = 0 writes = 0 async def r(): # read until we achive write successes nonlocal reads, writes while writes < 2: # print("current pre-reads", reads) await rwlock.reader_lock.acquire() try: reads += 1 # print("current reads", reads) await asyncio.sleep(0) finally: rwlock.reader_lock.release() async def w(): nonlocal reads, writes while reads == 0: await _wait() for _ in range(2): await _wait() # print("current pre-writes", reads) await rwlock.writer_lock.acquire() try: writes += 1 # print("current writes", reads) finally: rwlock.writer_lock.release() b1 = Bunch(r, N) b2 = Bunch(w, 1) await b1.wait_for_finished() await b2.wait_for_finished() assert writes == 2
def test_write_read_lock_multiple_tasks(loop): rwlock = RWLock(loop=loop) rl = rwlock.reader wl = rwlock.writer @asyncio.coroutine def coro(): with (yield from rl): assert not wl.locked assert rl.locked yield from asyncio.sleep(0.2, loop) with (yield from wl): assert wl.locked assert not rl.locked task = asyncio.Task(coro(), loop=loop) yield from asyncio.sleep(0.1, loop) yield from task assert not rl.locked assert not wl.locked
async def test_read_upgrade_write_release(loop): rwlock = RWLock() await rwlock.writer_lock.acquire() await rwlock.reader_lock.acquire() await rwlock.reader_lock.acquire() await rwlock.reader_lock.acquire() rwlock.reader_lock.release() assert rwlock.writer_lock.locked rwlock.writer_lock.release() assert not rwlock.writer_lock.locked assert rwlock.reader.locked with pytest.raises(RuntimeError): await rwlock.writer_lock.acquire() rwlock.reader_lock.release() rwlock.reader_lock.release()
async def test_race_multiple_writers(loop): seq = [] async def write_wait(lock): async with lock.reader: await asyncio.sleep(0.1) seq.append('READ') async with lock.writer: seq.append('START1') await asyncio.sleep(0.1) seq.append('FIN1') async def write(lock): await asyncio.sleep(0) # PY36 seems to run tasks in the wrong order. async with lock.writer: seq.append('START2') await asyncio.sleep(0.1) seq.append('FIN2') lock = RWLock(fast=True) await asyncio.gather(write_wait(lock), write(lock)) assert seq == ['READ', 'START2', 'FIN2', 'START1', 'FIN1']
async def test_readers_cancel(loop): rwlock = RWLock() rl = rwlock.reader wl = rwlock.writer async def coro(lock): async with lock: assert lock.locked await asyncio.sleep(0.2, loop) async with wl: assert wl.locked task_b = ensure_future(coro(rl)) task_c = ensure_future(coro(rl)) await asyncio.sleep(0.1, loop) task_b.cancel() assert not wl.locked await task_c assert task_c.done() assert not rl.locked assert not wl.locked
async def test_writer_then_reader_recursion(loop, fast_track): rwlock = RWLock(loop=loop, fast=fast_track) N = 5 locked = [] nlocked = [] async def f(): await rwlock.writer_lock.acquire() try: await rwlock.reader_lock.acquire() try: locked.append(1) await _wait(loop=loop) nlocked.append(len(locked)) await _wait(loop=loop) locked.pop(-1) finally: rwlock.reader_lock.release() finally: rwlock.writer_lock.release() await Bunch(f, N, loop=loop).wait_for_finished() assert max(nlocked) == 1
def test_readers_cancel(loop): rwlock = RWLock(loop=loop) rl = rwlock.reader wl = rwlock.writer @asyncio.coroutine def coro(lock): with (yield from lock): assert lock.locked yield from asyncio.sleep(0.2, loop) with (yield from wl): assert wl.locked task_b = ensure_future(coro(rl), loop=loop) task_c = ensure_future(coro(rl), loop=loop) yield from asyncio.sleep(0.1, loop) task_b.cancel() assert not wl.locked yield from task_c assert task_c.done() assert not rl.locked assert not wl.locked
def test_writer_success_with_statement(loop): # Verify that a writer can get access rwlock = RWLock(loop=loop) N = 5 reads = 0 writes = 0 @asyncio.coroutine def r(): # read until we achive write successes nonlocal reads, writes while writes < 2: # print("current pre-reads", reads) with (yield from rwlock.reader_lock): reads += 1 # print("current reads", reads) @asyncio.coroutine def w(): nonlocal reads, writes while reads == 0: yield from _wait(loop=loop) for i in range(2): yield from _wait(loop=loop) # print("current pre-writes", reads) with (yield from rwlock.writer_lock): writes += 1 b1 = Bunch(r, N, loop=loop) b2 = Bunch(w, 1, loop=loop) yield from b1.wait_for_finished() yield from b2.wait_for_finished() assert writes == 2
def test_release_unlocked(loop): rwlock = RWLock(loop=loop) with pytest.raises(RuntimeError): rwlock.reader_lock.release()
def test_ctor_noloop_writer(loop): asyncio.set_event_loop(loop) rwlock = RWLock().writer_lock assert rwlock._lock._loop is loop
def test_ctor_loop_writer(loop): rwlock = RWLock(loop=loop).writer_lock assert rwlock._lock._loop is loop
def test_ctor_loop_reader(loop): rwlock = RWLock(loop=loop).reader_lock assert rwlock._lock._loop is loop
def test_write_locked(loop): rwlock = RWLock(loop=loop) assert not rwlock.writer_lock.locked with (yield from rwlock.writer_lock): assert rwlock.writer_lock.locked