Skip to content

Commit d5418e9

Browse files
authored
[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 2ac3eec)
1 parent fbb0151 commit d5418e9

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

Lib/test/libregrtest/runtest_mp.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ def _runtest(self, test_name: str) -> MultiprocessResult:
269269
encoding = locale.getencoding()
270270
else:
271271
encoding = sys.stdout.encoding
272+
272273
# gh-94026: Write stdout+stderr to a tempfile as workaround for
273274
# non-blocking pipes on Emscripten with NodeJS.
274275
with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh:
@@ -277,7 +278,14 @@ def _runtest(self, test_name: str) -> MultiprocessResult:
277278
# Python finalization: too late for libregrtest.
278279
retcode = self._run_process(test_name, stdout_fh)
279280
stdout_fh.seek(0)
280-
stdout = stdout_fh.read().strip()
281+
282+
try:
283+
stdout = stdout_fh.read().strip()
284+
except Exception as exc:
285+
# gh-101634: Catch UnicodeDecodeError if stdout cannot be
286+
# decoded from encoding
287+
err_msg = f"Cannot read process stdout: {exc}"
288+
return self.mp_result_error(ChildError(test_name), '', err_msg)
281289

282290
if retcode is None:
283291
return self.mp_result_error(Timeout(test_name), stdout)
@@ -452,6 +460,8 @@ def _process_result(self, item: QueueOutput) -> bool:
452460
# Thread got an exception
453461
format_exc = item[1]
454462
print_warning(f"regrtest worker thread failed: {format_exc}")
463+
result = ChildError("<regrtest worker>")
464+
self.regrtest.accumulate_result(result)
455465
return True
456466

457467
self.test_index += 1

Lib/test/test_regrtest.py

+36
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import contextlib
88
import glob
99
import io
10+
import locale
1011
import os.path
1112
import platform
1213
import re
@@ -1518,6 +1519,41 @@ def test_cleanup(self):
15181519
for name in names:
15191520
self.assertFalse(os.path.exists(name), name)
15201521

1522+
def test_mp_decode_error(self):
1523+
# gh-101634: If a worker stdout cannot be decoded, report a failed test
1524+
# and a non-zero exit code.
1525+
if sys.platform == 'win32':
1526+
encoding = locale.getencoding()
1527+
else:
1528+
encoding = sys.stdout.encoding
1529+
if encoding is None:
1530+
encoding = sys.__stdout__.encoding
1531+
if encoding is None:
1532+
self.skipTest(f"cannot get regrtest worker encoding")
1533+
1534+
nonascii = b"byte:\xa0\xa9\xff\n"
1535+
try:
1536+
nonascii.decode(encoding)
1537+
except UnicodeDecodeError:
1538+
pass
1539+
else:
1540+
self.skipTest(f"{encoding} can decode non-ASCII bytes {nonascii!a}")
1541+
1542+
code = textwrap.dedent(fr"""
1543+
import sys
1544+
# bytes which cannot be decoded from UTF-8
1545+
nonascii = {nonascii!a}
1546+
sys.stdout.buffer.write(nonascii)
1547+
sys.stdout.buffer.flush()
1548+
""")
1549+
testname = self.create_test(code=code)
1550+
1551+
output = self.run_tests("--fail-env-changed", "-v", "-j1", testname,
1552+
exitcode=EXITCODE_BAD_TEST)
1553+
self.check_executed_tests(output, [testname],
1554+
failed=[testname],
1555+
randomize=True)
1556+
15211557

15221558
class TestUtils(unittest.TestCase):
15231559
def test_format_duration(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When running the Python test suite with ``-jN`` option, if a worker stdout
2+
cannot be decoded from the locale encoding report a failed testn so the
3+
exitcode is non-zero. Patch by Victor Stinner.

0 commit comments

Comments
 (0)