From 7d61c967c9663d12deb7c7de2b48e17d6041308d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 04:26:52 +0200 Subject: [PATCH] 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. (cherry picked from commit 2ac3eec103cf450aaaebeb932e51155d2e7fb37b) --- Lib/test/libregrtest/runtest_mp.py | 12 ++++++- Lib/test/test_regrtest.py | 36 +++++++++++++++++++ ...-06-28-02-51-08.gh-issue-101634.Rayczr.rst | 3 ++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index c6a4dae2df86a9..8587e64e5153e6 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -269,6 +269,7 @@ def _runtest(self, test_name: str) -> MultiprocessResult: 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: @@ -277,7 +278,14 @@ def _runtest(self, test_name: str) -> MultiprocessResult: # Python finalization: too late for libregrtest. retcode = self._run_process(test_name, stdout_fh) 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) @@ -452,6 +460,8 @@ def _process_result(self, item: QueueOutput) -> bool: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") + result = ChildError("") + 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 f692dd1e3e65b4..78552590a7289c 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -7,6 +7,7 @@ import contextlib import glob import io +import locale import os.path import platform import re @@ -1518,6 +1519,41 @@ def test_cleanup(self): for name in names: self.assertFalse(os.path.exists(name), name) + 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): diff --git a/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst new file mode 100644 index 00000000000000..6fbfc84c19e1b8 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst @@ -0,0 +1,3 @@ +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. Patch by Victor Stinner. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy