From 5daba6268341406727465d538028ffbe988b26c5 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 Jan 2025 11:22:23 -0500 Subject: [PATCH] More gracefully handle crashes in pytest. When the pytest executable is executing, there is some possibility that it can crash (due to a bug in C extensions, for instance). In the current code, this circumstance causes the main colcon property to return a non-zero exit number. But that doesn't seem correct; colcon didn't fail, one of the tests did. The test should be marked as failing, but colcon itself should return a success code. Additionally, we notice that if a e.g. ctest test crashes, colcon returns 0. The reason this happens only with pytest is because pytest doesn't have a mechanism to suppress these kinds of errors. Thus if the python interpreter in the pytest process crashes, pytest returns the segmentation fault number (-11 on Linux, 0xc0000005 on Windows). Handle this by explicitly capturing this fault number, and setting the test to failed. Unfortunately there are no convenient constants in Python that I could find for these numbers, so they are hardcoded here. This does change the user-visible functioning of colcon, but I believe it does so for the better, and it is a bit of a corner case. Signed-off-by: Chris Lalancette --- colcon_core/task/python/test/pytest.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/colcon_core/task/python/test/pytest.py b/colcon_core/task/python/test/pytest.py index 335e2140b..817e4a573 100644 --- a/colcon_core/task/python/test/pytest.py +++ b/colcon_core/task/python/test/pytest.py @@ -161,9 +161,6 @@ async def step(self, context, env, setup_py_data): # noqa: D102 # support pytest < 5.0 from _pytest.main import EXIT_TESTSFAILED EXIT_CODE_TESTS_FAILED = EXIT_TESTSFAILED # noqa: N806 - if completed.returncode == EXIT_CODE_TESTS_FAILED: - context.put_event_into_queue( - TestFailure(context.pkg.name)) try: from _pytest.main import ExitCode @@ -172,7 +169,15 @@ async def step(self, context, env, setup_py_data): # noqa: D102 # support pytest < 5.0 from _pytest.main import EXIT_NOTESTSCOLLECTED EXIT_CODE_NO_TESTS = EXIT_NOTESTSCOLLECTED # noqa: N806 - if completed.returncode not in ( - EXIT_CODE_NO_TESTS, EXIT_CODE_TESTS_FAILED + + if sys.platform == 'win32': + EXIT_CODE_TESTS_CRASHED = 3221225477 + else: + EXIT_CODE_TESTS_CRASHED = -11 + + if completed.returncode in ( + EXIT_CODE_TESTS_FAILED, EXIT_CODE_TESTS_CRASHED ): + context.put_event_into_queue(TestFailure(context.pkg.name)) + elif completed.returncode != EXIT_CODE_NO_TESTS: return completed.returncode