-
-
Notifications
You must be signed in to change notification settings - Fork 25
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 test timeout support #53
Comments
Actually.... this doesn't need help from Trio, if we're clever. It's not the most elegant thing, but we can start a timer thread running, and then if the timeout expires it can call back into Trio. Of course we'll also want to be able to kill it early, so something like, a thread blocked in def timeout_thread(wake_sock, timeout, trio_token, cancel_scope):
readable, _, _ = select.select([wake_sock], [], [], timeout)
if not readable:
# we were woken by the timeout expiring
try:
trio_token.run_sync_soon(cancel_scope.cancel)
except trio.RunFinishedError:
pass
async with trio.open_nursery() as nursery:
a, b = socket.socketpair() # blocking sockets
trio_token = trio.hazmat.current_trio_token()
try:
with trio.open_cancel_scope() as timeout_cancel_scope:
nursery.start_soon(trio.run_sync_in_worker_thread, timeout_thread, b, timeout, trio_token, timeout_cancel_scope, limiter=UNLIMITED)
# ... do actual test here ...
finally:
a.send(b"x")
if timeout_cancel_scope.cancelled_caught:
raise ... This does require that the Trio scheduler be functioning properly, but so would a more intrusive version baked into the Trio scheduler. This also has the advantage that by being in a third-party library we have a lot of flexibility to adjust the response to the timeout however we want – e.g. instead of just cancelling the test, we could have it capture and print a snapshot of the task tree with stacktraces. Or try cancelling after X seconds, and then if the test is still running after another Y seconds (i.e. it's ignoring the cancellation), use harsher methods to disable pytest's output capturing, dump debugging information to the screen, and then call |
In python-trio/trio#168 I suggested that we might want to have two separate timeouts – an idle timeout and a global timeout:
On further consideration, I think a deadlock detector like in python-trio/trio#1085 would be a better solution for the "idle timeout" use cases, so maybe pytest-trio should just focus on providing a global timeout. |
Whenever the trio_timeout option is enabled, this plugin will hook into requests from pytest-timeout to set a timeout. It will then start a thread in the background that, after the timeout has reached, will inject a system task in the test loop. This system task will collect stacktraces for all tasks and raise an exception that will terminate the test. The timeout thread is reused for other tests as well to not incur a startup cost for every test. Since this feature integrates with pytest-timeout, it also honors things like whether a debugger is attached or not. Drawbacks: - Ideally, whether trio does timeouts should not be a global option, but would be better suited for the timeout-method in pytest-timeout. This would require a change in pytest-timeout to let plugins register other timeout methods. - This method requires a functioning loop. Fixes python-trio#53
Whenever the trio_timeout option is enabled, this plugin will hook into requests from pytest-timeout to set a timeout. It will then start a thread in the background that, after the timeout has reached, will inject a system task in the test loop. This system task will collect stacktraces for all tasks and raise an exception that will terminate the test. The timeout thread is reused for other tests as well to not incur a startup cost for every test. Since this feature integrates with pytest-timeout, it also honors things like whether a debugger is attached or not. Drawbacks: - Ideally, whether trio does timeouts should not be a global option, but would be better suited for the timeout-method in pytest-timeout. This would require a change in pytest-timeout to let plugins register other timeout methods. - This method requires a functioning loop. Fixes python-trio#53
This will need some help from Trio – see python-trio/trio#168
The text was updated successfully, but these errors were encountered: