diff options
author | Victor Stinner <vstinner@python.org> | 2023-06-28 02:26:52 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-28 02:26:52 (GMT) |
commit | 2ac3eec103cf450aaaebeb932e51155d2e7fb37b (patch) | |
tree | 31efe761a024723ab093eb83a9a081106e858502 /Lib/test | |
parent | 3f8483cad2f3b94600c3ecf3f0bb220bb1e61d7d (diff) | |
download | cpython-2ac3eec103cf450aaaebeb932e51155d2e7fb37b.zip cpython-2ac3eec103cf450aaaebeb932e51155d2e7fb37b.tar.gz cpython-2ac3eec103cf450aaaebeb932e51155d2e7fb37b.tar.bz2 |
gh-101634: regrtest reports decoding error as failed test (#106169)
When running the Python test suite with -jN option, if a worker stdout
cannot be decoded from the locale encoding report a failed testn so the
exitcode is non-zero.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/libregrtest/runtest_mp.py | 12 | ||||
-rw-r--r-- | Lib/test/test_regrtest.py | 36 |
2 files changed, 47 insertions, 1 deletions
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index a12fcb4..62e6c6d 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -277,6 +277,7 @@ class TestWorkerProcess(threading.Thread): encoding = locale.getencoding() else: encoding = sys.stdout.encoding + # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: @@ -298,7 +299,14 @@ class TestWorkerProcess(threading.Thread): retcode = self._run_process(test_name, None, stdout_fh) tmp_files = () stdout_fh.seek(0) - stdout = stdout_fh.read().strip() + + try: + stdout = stdout_fh.read().strip() + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + err_msg = f"Cannot read process stdout: {exc}" + return self.mp_result_error(ChildError(test_name), '', err_msg) if retcode is None: return self.mp_result_error(Timeout(test_name), stdout) @@ -481,6 +489,8 @@ class MultiprocessTestRunner: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") + result = ChildError("<regrtest worker>") + self.regrtest.accumulate_result(result) return True self.test_index += 1 diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index ac49fba..806b932 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -7,6 +7,7 @@ Note: test_regrtest cannot be run twice in parallel. import contextlib import glob import io +import locale import os.path import platform import re @@ -1551,6 +1552,41 @@ class ArgsTestCase(BaseTestCase): f"files (1): mytmpfile", output) + def test_mp_decode_error(self): + # gh-101634: If a worker stdout cannot be decoded, report a failed test + # and a non-zero exit code. + if sys.platform == 'win32': + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding + if encoding is None: + encoding = sys.__stdout__.encoding + if encoding is None: + self.skipTest(f"cannot get regrtest worker encoding") + + nonascii = b"byte:\xa0\xa9\xff\n" + try: + nonascii.decode(encoding) + except UnicodeDecodeError: + pass + else: + self.skipTest(f"{encoding} can decode non-ASCII bytes {nonascii!a}") + + code = textwrap.dedent(fr""" + import sys + # bytes which cannot be decoded from UTF-8 + nonascii = {nonascii!a} + sys.stdout.buffer.write(nonascii) + sys.stdout.buffer.flush() + """) + testname = self.create_test(code=code) + + output = self.run_tests("--fail-env-changed", "-v", "-j1", testname, + exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, [testname], + failed=[testname], + randomize=True) + class TestUtils(unittest.TestCase): def test_format_duration(self): |