Skip to content

Commit ddc08ba

Browse files
committed
add advance_time fixture and test (closes pytest-dev#83, pytest-dev#95, pytest-dev#96 pytest-dev#110)
1 parent f35d06b commit ddc08ba

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

pytest_asyncio/plugin.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,44 @@ def pytest_runtest_setup(item):
201201
}
202202

203203

204+
class EventLoopClockAdvancer:
205+
"""
206+
A helper object that when called will advance the event loop's time. If the
207+
call is awaited, the caller task will wait an iteration for the update to
208+
wake up any awaiting handlers.
209+
"""
210+
__slots__ = ("offset", "loop", "_base_time",)
211+
212+
def __init__(self, loop):
213+
self.offset = 0.0
214+
self._base_time = loop.time
215+
self.loop = loop
216+
217+
# incorporate offset timing into the event loop
218+
self.loop.time = self.time
219+
220+
def time(self):
221+
"""
222+
Return the time according to the event loop's clock. The time is
223+
adjusted by an offset.
224+
"""
225+
return self._base_time() + self.offset
226+
227+
def __call__(self, seconds):
228+
"""
229+
Advance time by a given offset in seconds. Returns an awaitable
230+
that will complete after all tasks scheduled for after advancement
231+
of time are proceeding.
232+
"""
233+
if seconds > 0:
234+
# advance the clock by the given offset
235+
self.offset += abs(seconds)
236+
237+
# Once the clock is adjusted, new tasks may have just been
238+
# scheduled for running in the next pass through the event loop
239+
return self.loop.create_task(asyncio.sleep(0))
240+
241+
204242
@pytest.yield_fixture
205243
def event_loop(request):
206244
"""Create an instance of the default event loop for each test case."""
@@ -237,3 +275,8 @@ def factory():
237275

238276
return port
239277
return factory
278+
279+
280+
@pytest.fixture
281+
def advance_time(event_loop):
282+
return EventLoopClockAdvancer(event_loop)

tests/test_simple_35.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,24 @@ async def test_asyncio_marker_method(self, event_loop):
8686
def test_async_close_loop(event_loop):
8787
event_loop.close()
8888
return 'ok'
89+
90+
91+
@pytest.mark.asyncio
92+
async def test_advance_time_fixture(event_loop, advance_time):
93+
"""
94+
Test the `advance_time` fixture
95+
"""
96+
# A task is created that will sleep some number of seconds
97+
SLEEP_TIME = 10
98+
99+
# create the task
100+
task = event_loop.create_task(asyncio.sleep(SLEEP_TIME))
101+
assert not task.done()
102+
103+
# start the task
104+
await advance_time(0)
105+
assert not task.done()
106+
107+
# process the timeout
108+
await advance_time(SLEEP_TIME)
109+
assert task.done()

0 commit comments

Comments
 (0)