Skip to content

Commit e51308a

Browse files
committed
gh-47798: Test BrokenPipe-mid-write and timeout-after-I/O-completes paths
test_pipeline_brokenpipe_mid_input_write: large input where the first command reads one byte then exits, so the I/O loop's stdin write path hits BrokenPipeError mid-write and must recover. test_pipeline_timeout_after_io_completes: the final command closes its stdout (so the I/O loop sees EOF and finishes) then sleeps, so the per-process wait() is what times out rather than the I/O loop.
1 parent 03c2da4 commit e51308a

1 file changed

Lines changed: 34 additions & 0 deletions

File tree

Lib/test/test_subprocess.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2745,6 +2745,40 @@ def test_pipeline_middle_command_exits_early(self):
27452745
self.assertEqual(result.returncodes[1], 0)
27462746
self.assertEqual(result.returncodes[2], 0)
27472747

2748+
def test_pipeline_brokenpipe_mid_input_write(self):
2749+
"""The first command exits while input is still being written.
2750+
2751+
Exercises the BrokenPipeError handler in the I/O loop's stdin
2752+
write path: the input is larger than typical pipe buffers, the
2753+
first command reads a single byte then exits, and the
2754+
remaining writes must fail gracefully.
2755+
"""
2756+
big = b"x" * (4 * 1024 * 1024)
2757+
result = subprocess.run_pipeline(
2758+
[sys.executable, "-c",
2759+
"import sys; sys.stdin.buffer.read(1); sys.exit(0)"],
2760+
[sys.executable, "-c", "import sys; sys.stdin.read()"],
2761+
input=big, capture_output=True, timeout=60,
2762+
)
2763+
self.assertEqual(result.returncodes, (0, 0))
2764+
2765+
def test_pipeline_timeout_after_io_completes(self):
2766+
"""Timeout fires after I/O completes but a process is still running.
2767+
2768+
The final command closes its stdout (so the I/O loop sees EOF
2769+
and finishes) and then sleeps, so the per-process wait() is
2770+
what times out rather than the I/O loop.
2771+
"""
2772+
with self.assertRaises(subprocess.TimeoutExpired) as cm:
2773+
subprocess.run_pipeline(
2774+
[sys.executable, "-c", "pass"],
2775+
[sys.executable, "-c",
2776+
"import sys, os, time; "
2777+
"sys.stdout.close(); os.close(1); time.sleep(60)"],
2778+
stdout=subprocess.PIPE, timeout=0.5,
2779+
)
2780+
self.assertIsNotNone(cm.exception.output)
2781+
27482782

27492783
class PipelineCommandTestCase(BaseTestCase):
27502784
"""Tests for subprocess.PipelineCommand and its run_pipeline integration."""

0 commit comments

Comments
 (0)