Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing tests for some corner-case uses #37

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions tests/test_corner_cases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import pytest
import asyncio
import contextlib

from aiorwlock import RWLock, create_future


if hasattr(asyncio, 'ensure_future'):
ensure_future = asyncio.ensure_future
else:
ensure_future = asyncio.async # Deprecated since 3.4.4


@contextlib.contextmanager
def should_fail(timeout, loop):
task = asyncio.Task.current_task(loop)

handle = loop.call_later(timeout, task.cancel)
try:
yield
except asyncio.CancelledError:
handle.cancel()
return
else:
assert False, ("Inner task expected to be cancelled", task)


@pytest.mark.run_loop
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


@pytest.mark.run_loop
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


@pytest.mark.run_loop
def test_writers_deadlock(loop):
rwlock = RWLock(loop=loop)
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

@asyncio.coroutine
def coro():
with (yield from wl):
assert wl.locked
yield from asyncio.sleep(.2, loop)

with (yield from rl):
assert rl.locked
task_b = ensure_future(coro(), loop=loop)
task_c = ensure_future(coro(), loop=loop)
yield from asyncio.sleep(0.1, loop)
# cancel lock waiter right after release
task_b.cancel()
assert not rl.locked

# wait task_c to complete
yield from asyncio.sleep(0.3, loop)
assert task_c.done()
assert not rl.locked
assert not wl.locked