[3.11] gh-101634: regrtest reports decoding error as failed test (#106169) (#106175)

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 2ac3eec103)
This commit is contained in:
Victor Stinner 2023-06-28 04:58:34 +02:00 committed by GitHub
parent fbb0151e5e
commit d5418e97fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 1 deletions

View file

@ -269,6 +269,7 @@ class TestWorkerProcess(threading.Thread):
encoding = locale.getencoding() encoding = locale.getencoding()
else: else:
encoding = sys.stdout.encoding encoding = sys.stdout.encoding
# gh-94026: Write stdout+stderr to a tempfile as workaround for # gh-94026: Write stdout+stderr to a tempfile as workaround for
# non-blocking pipes on Emscripten with NodeJS. # non-blocking pipes on Emscripten with NodeJS.
with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh:
@ -277,7 +278,14 @@ class TestWorkerProcess(threading.Thread):
# Python finalization: too late for libregrtest. # Python finalization: too late for libregrtest.
retcode = self._run_process(test_name, stdout_fh) retcode = self._run_process(test_name, stdout_fh)
stdout_fh.seek(0) 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: if retcode is None:
return self.mp_result_error(Timeout(test_name), stdout) return self.mp_result_error(Timeout(test_name), stdout)
@ -452,6 +460,8 @@ class MultiprocessTestRunner:
# Thread got an exception # Thread got an exception
format_exc = item[1] format_exc = item[1]
print_warning(f"regrtest worker thread failed: {format_exc}") print_warning(f"regrtest worker thread failed: {format_exc}")
result = ChildError("<regrtest worker>")
self.regrtest.accumulate_result(result)
return True return True
self.test_index += 1 self.test_index += 1

View file

@ -7,6 +7,7 @@ Note: test_regrtest cannot be run twice in parallel.
import contextlib import contextlib
import glob import glob
import io import io
import locale
import os.path import os.path
import platform import platform
import re import re
@ -1518,6 +1519,41 @@ class ArgsTestCase(BaseTestCase):
for name in names: for name in names:
self.assertFalse(os.path.exists(name), name) 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): class TestUtils(unittest.TestCase):
def test_format_duration(self): def test_format_duration(self):

View file

@ -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.