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

Add clock event loop as default #110

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
71701e1
Add ClockEventLoop class with fixture and test (close #95)
derekbrokeit Sep 10, 2018
3d34037
add doc string to ClockEventLoop
derekbrokeit Sep 10, 2018
a723020
improve name of nap function in test_clock_loop
derekbrokeit Jan 4, 2019
997afe2
fix ClockEventLoop being a selector loop, instead use default of asyncio
derekbrokeit Jan 4, 2019
6fbeb60
refactor ClockEventLoop to only advance time but otherwise act as sta…
derekbrokeit Jan 4, 2019
7d94f14
add asyncio_clock mark so that coroutines can be run in a ClockEventL…
derekbrokeit Jan 4, 2019
8841d15
fix test_clock_advance_time for changes to ClockEventLoop interface
derekbrokeit Jan 4, 2019
98c6bf8
add simple tests for asyncio_clock mark and clock_event_loop fixture
derekbrokeit Jan 4, 2019
d757d19
Merge remote-tracking branch 'remotes/base/master' into add-clock-eve…
derekbrokeit Jan 4, 2019
ce6a2c7
rearrange ClockEventLoop.advance_time so that extra iterations are no…
derekbrokeit Jan 4, 2019
1a8b887
calls to asyncio.sleep in ClockEventLoop force the sleeping loop
derekbrokeit Jan 4, 2019
f3efb64
remove ValueError from ClockEventLoop.advance_time in favor of return…
derekbrokeit Jan 7, 2019
8452d41
Fixes for given questions posed
derekbrokeit Jan 9, 2019
559e883
further simplify advance_time method
derekbrokeit Jan 9, 2019
1d3cd51
rework advance_time to reduce complexity
derekbrokeit Jan 9, 2019
ed8b05d
make the clock_event_loop test easier to read
derekbrokeit Jan 9, 2019
c3df015
refactor clock_event_loop fixture to become default event_loop
derekbrokeit Feb 4, 2019
91466b4
improve documentation
derekbrokeit Feb 4, 2019
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
55 changes: 55 additions & 0 deletions pytest_asyncio/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,64 @@ def pytest_runtest_setup(item):
}


def _event_loop_policy():
"""
Create a new class for ClockEventLoopPolicy based on the current
class-type produced by `asyncio.get_event_loop_policy()`. This is important
for instances in which the enent-loop-policy has been changed.
"""
class ClockEventLoopPolicy(asyncio.get_event_loop_policy().__class__):
"A custom event loop policy for ClockEventLoop"

def new_event_loop(self):
parent_loop = super().new_event_loop()
parent_loop.close()

class ClockEventLoop(parent_loop.__class__):
"""
A custom event loop that explicitly advances time when requested. Otherwise,
this event loop advances time as expected.
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._clockoffset = 0

def time(self):
"""
Return the time according the event loop's clock.

This time is adjusted by the stored offset that allows for advancement
with `advance_time`.
"""
return super().time() + self._clockoffset

def advance_time(self, seconds):
'''
Advance time by a given offset in seconds. Returns an awaitable
that will complete after all tasks scheduled for after advancement
of time are proceeding.
'''
if seconds > 0:
# advance the clock by the given offset
self._clockoffset += seconds

# Once the clock is adjusted, new tasks may have just been
# scheduled for running in the next pass through the event loop
return self.create_task(asyncio.sleep(0))

# return the new event loop
return ClockEventLoop()

# return the new event loop policy
return ClockEventLoopPolicy()


@pytest.yield_fixture
def event_loop(request):
"""Create an instance of the default event loop for each test case."""
# reset the event loop policy: modify existing policy to give time advancement
asyncio.set_event_loop_policy(_event_loop_policy())
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
Expand Down
21 changes: 21 additions & 0 deletions tests/test_simple_35.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,24 @@ async def test_asyncio_marker_method(self, event_loop):
def test_async_close_loop(event_loop):
event_loop.close()
return 'ok'


@pytest.mark.asyncio
async def test_event_loop_advance_time(event_loop):
"""
Test the sliding time event loop fixture
"""
# A task is created that will sleep some number of seconds
SLEEP_TIME = 10

# create the task
task = event_loop.create_task(asyncio.sleep(SLEEP_TIME))
assert not task.done()

# start the task
await event_loop.advance_time(0)
assert not task.done()

# process the timeout
await event_loop.advance_time(SLEEP_TIME)
assert task.done()