Skip to content

Commit

Permalink
More gracefully handle crashes in pytest.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
clalancette committed Jan 3, 2025
1 parent a74fa97 commit 5daba62
Showing 1 changed file with 10 additions and 5 deletions.
15 changes: 10 additions & 5 deletions colcon_core/task/python/test/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

0 comments on commit 5daba62

Please sign in to comment.