From af788440e15bfa3c810509d2205cd3fbb3d66bd8 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sat, 27 Apr 2024 11:22:08 -0700 Subject: [PATCH] gateway: Test concurrent rinfo for main_thread_only Add test coverage for a bug triggered by pytest-cov when it tried to call _rinfo after the gateway was already busy with a remote_exec call: https://github.com/pytest-dev/pytest-xdist/issues/1071 --- testing/test_gateway.py | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/testing/test_gateway.py b/testing/test_gateway.py index 4291404e..eeb6456f 100644 --- a/testing/test_gateway.py +++ b/testing/test_gateway.py @@ -645,3 +645,47 @@ def test_main_thread_only_concurrent_remote_exec_deadlock( ch.close() gw.exit() gw.join() + + +def test_concurrent_rinfo(execmodel: gateway_base.ExecModel) -> None: + # Use a temporary Group to force the desired execmodel, since + # groups used by fixtures tend to use the thread execmodel. + group = execnet.Group(execmodel=execmodel.backend) + gw = group.makegateway(f"execmodel={execmodel.backend}//popen") + + # For main_thread_only _rinfo will deadlock unless the gateway + # has cached the result earlier, but only if sleep_time + # exceeds the 1 second grace period in the WorkerGateway + # _local_schedulexec method. For other execmodels, a shorter + # sleep_time is sufficient to test concurrent _rinfo. + sleep_time = 1.5 if execmodel.backend == "main_thread_only" else 0.5 + try: + if execmodel.backend == "main_thread_only": + # Cache rinfo like pytest-dist does for backward compatibility, + # in order to prevent a deadlock error when pytest-cov requests + # rinfo while the main thread is busy with the pytest-xdist + # WorkerController's remote_exec call. + gw._rinfo() + assert hasattr(gw, "_cache_rinfo") + + ch = gw.remote_exec( + """ + import os, time + time.sleep({sleep_time}) + channel.send(os.getpid()) + """.format( + sleep_time=sleep_time + ) + ) + rinfo = gw._rinfo() + try: + res = ch.receive() + finally: + ch.close() + ch.waitclose() + + assert res == rinfo.pid + finally: + gw.exit() + gw.join() + group.terminate(0.5)