diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -16,7 +16,8 @@ from test.support import make_legacy_pyc, strip_python_stderr # Executing the interpreter in a subprocess -def _assert_python(expected_success, *args, **env_vars): +def _assert_python(expected_success, *args, preexec_fn=None, + **env_vars): cmd_line = [sys.executable] if not env_vars: cmd_line.append('-E') @@ -31,7 +32,7 @@ cmd_line.extend(args) p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=env) + env=env, preexec_fn=preexec_fn) try: out, err = p.communicate() finally: diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -48,7 +48,8 @@ support.unlink(filename) class FaultHandlerTests(unittest.TestCase): - def get_output(self, code, filename=None): + def get_output(self, expect_success, code, filename=None, + extra_args=(), env_vars={}): """ Run the specified code in Python (in a new child process) and read the output from the standard error or from a file (if filename is set). @@ -58,13 +59,12 @@ build, and replace "Current thread 0x00007f8d8fbd9700" by "Current thread XXX". """ - options = {} - if prepare_subprocess: - options['preexec_fn'] = prepare_subprocess - process = script_helper.spawn_python('-c', code, **options) - stdout, stderr = process.communicate() - exitcode = process.wait() - output = support.strip_python_stderr(stdout) + + args = list(extra_args) + ['-c', code] + exitcode, stdout, stderr = script_helper._assert_python( + expect_success, *args, preexec_fn=prepare_subprocess, **env_vars) + + output = support.strip_python_stderr(stderr) output = output.decode('ascii', 'backslashreplace') if filename: self.assertEqual(output, '') @@ -77,7 +77,8 @@ return output.splitlines(), exitcode def check_fatal_error(self, code, line_number, name_regex, - filename=None, all_threads=True, other_regex=None): + filename=None, all_threads=True, other_regex=None, + extra_args=(), env_vars={}): """ Check that the fault handler for fatal errors is enabled and check the traceback from the child process output. @@ -100,10 +101,28 @@ header=re.escape(header)) if other_regex: regex += '|' + other_regex - output, exitcode = self.get_output(code, filename) + output, exitcode = self.get_output(False, code, filename, + extra_args, env_vars) output = '\n'.join(output) self.assertRegex(output, regex) - self.assertNotEqual(exitcode, 0) + + def test_X_option(self): + self.check_fatal_error(""" +import faulthandler +faulthandler._sigsegv() +""".strip(), + 2, + 'Segmentation fault', + extra_args=['-X', 'faulthandler']) + + def test_env_var(self): + self.check_fatal_error(""" +import sys, os, faulthandler +faulthandler._sigsegv() +""".strip(), + 2, + 'Segmentation fault', + env_vars={'PYTHONFAULTHANDLER':'YesPlease'}) def test_read_null(self): self.check_fatal_error(""" @@ -228,11 +247,10 @@ faulthandler._read_null() """.strip() not_expected = 'Fatal Python error' - stderr, exitcode = self.get_output(code) + stderr, exitcode = self.get_output(False, code) stder = '\n'.join(stderr) self.assertTrue(not_expected not in stderr, "%r is present in %r" % (not_expected, stderr)) - self.assertNotEqual(exitcode, 0) def test_is_enabled(self): orig_stderr = sys.stderr @@ -290,9 +308,8 @@ ' File "", line 11 in funcA', ' File "", line 13 in ' ] - trace, exitcode = self.get_output(code, filename) + trace, exitcode = self.get_output(True, code, filename) self.assertEqual(trace, expected) - self.assertEqual(exitcode, 0) def test_dump_traceback(self): self.check_dump_traceback(None) @@ -340,7 +357,7 @@ waiter.join() """.strip() code = code.format(filename=repr(filename)) - output, exitcode = self.get_output(code, filename) + output, exitcode = self.get_output(True, code, filename) output = '\n'.join(output) if filename: lineno = 8 @@ -359,7 +376,6 @@ """.strip() regex = regex.format(lineno=lineno) self.assertRegex(output, regex) - self.assertEqual(exitcode, 0) def test_dump_traceback_threads(self): self.check_dump_traceback_threads(None) @@ -409,7 +425,7 @@ has_filename=bool(filename), filename=repr(filename), ) - trace, exitcode = self.get_output(code, filename) + trace, exitcode = self.get_output(True, code, filename) trace = '\n'.join(trace) if not cancel: @@ -421,7 +437,6 @@ self.assertRegex(trace, regex) else: self.assertEqual(trace, '') - self.assertEqual(exitcode, 0) @unittest.skipIf(not hasattr(faulthandler, 'dump_tracebacks_later'), 'need faulthandler.dump_tracebacks_later()') @@ -514,7 +529,7 @@ unregister=unregister, chain=chain, ) - trace, exitcode = self.get_output(code, filename) + trace, exitcode = self.get_output(not unregister, code, filename) trace = '\n'.join(trace) if not unregister: if all_threads: @@ -525,10 +540,6 @@ self.assertRegex(trace, regex) else: self.assertEqual(trace, '') - if unregister: - self.assertNotEqual(exitcode, 0) - else: - self.assertEqual(exitcode, 0) def test_register(self): self.check_register()