summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/libregrtest/runtest_mp.py12
-rw-r--r--Lib/test/test_regrtest.py36
-rw-r--r--Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst3
3 files changed, 50 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):
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 0000000..6fbfc84
--- /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.