Closed ja8zyjits closed 5 years ago
Hi,
In your example, there is a race condition between the moment stop() is called and a second iteration of the loop in sync_function() runs:
import asyncio
import asynctest
class WorkingModel:
def __init__(self, interval=10):
self._interval = interval
self._status = None
self._statrted = False
async def start(self):
self._statrted = True
self._sync = asyncio.ensure_future(self.sync_function())
print("started")
async def sync_function(self):
while self._statrted:
print(f"going to sleep for {self._interval}")
await asyncio.sleep(self._interval)
self._status = 1
async def stop(self):
self._statrted = False
print("stop called, self._statrted set to False")
print("going to await the bg task self._sync")
await self._sync
print("awaited the bg task self._sync")
class MainTest(asynctest.ClockedTestCase):
async def test_main(self):
working_model = WorkingModel()
await working_model.start()
print("going to advance")
await self.advance(10)
print("advanced of 10")
self.assertEqual(working_model._status, 1)
await working_model.stop()
"""
output is:
started
going to advance
going to sleep for 10
going to sleep for 10
advanced of 10
stop called, self._statrted set to False
going to await the bg task self._sync
"""
In the output, we can see that a second sleep() is called before _stop is called, however, you never advance the clock anymore, it just waits for this sleep.
When using ClockedTestCase, the clock never moves unless you call advance().
you must thus call self.advance(10) once again after calling working_model.stop(). However, since there's yet another deadlock because stop waits for the second sleep() to finish, it must be executed concurrently.
you can do something like:
advance = asyncio.ensure_future(self.advance(10))
await working_model.stop()
await advance
But there's still a theoretical race condition between stop() and this second advance().
I'm closing the issue since ClockedTestCase works as expected. If you believe we should change something, feel free to comment and reopen the issue.
@Martiusweb Thanks for your prompt response. May be we need a bit more descriptive documentation regarding the utility of self.advance
and its use cases.
True, I added a notice in the doc and tutorial.
The problem
I am trying to use the
ClockedTestCase
. Iam trying to fast forward theasyncio.sleep
in my code while testing. But iam not able to make it work.class WorkingModel: def init(self, interval=10): self._interval = interval self._status = None self._statrted = False
When iam running the tests with
python -m unittest
the script just hangs.Nothing much happens
while the normal
asynctest.TestCase
works but it takes time like 20 seconds (10+10)class MainTest(asynctest.ClockedTestCase):
class MainTest(asynctest.TestCase): async def test_main(self): working_model = script.WorkingModel() await working_model.start()
await self.advance(10)
if name=="main": unittest.main()
Support information
3.6.7
It would be really nice if I could make the
self.advance
feature work.