Skip to content

Commit af28f82

Browse files
committed
gh-47798: Test PipelineError signal __str__ and mid-pipeline spawn failure
test_pipeline_error_str_signal covers the negative-returncode rendering in PipelineError.__str__. test_pipeline_spawn_failure_cleans_up exercises the run_pipeline finally-block cleanup when a later stage fails to exec: stage 0 is already running and sleeping, stage 1's executable does not exist, and the call must return promptly with the OSError rather than hang on stage 0.
1 parent 6ef0292 commit af28f82

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

Lib/test/test_subprocess.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,37 @@ def test_pipeline_error_str(self):
22842284
error_str = str(e)
22852285
self.assertIn('Pipeline failed', error_str)
22862286

2287+
@unittest.skipIf(mswindows, "negative returncodes are POSIX signal-deaths")
2288+
def test_pipeline_error_str_signal(self):
2289+
"""PipelineError renders negative returncodes as signal deaths,
2290+
matching CalledProcessError."""
2291+
err = subprocess.PipelineError(
2292+
[['a'], ['b']], [0, -signal.SIGTERM])
2293+
msg = str(err)
2294+
self.assertIn('died with', msg)
2295+
self.assertIn('SIGTERM', msg)
2296+
self.assertNotIn('-15', msg)
2297+
2298+
def test_pipeline_spawn_failure_cleans_up(self):
2299+
"""Popen failing mid-pipeline propagates and reaps earlier stages.
2300+
2301+
Stage 0 starts and would sleep 60s; stage 1's executable does not
2302+
exist so Popen raises before stage 1 ever runs. The finally block
2303+
must kill and wait on stage 0 so this call returns promptly rather
2304+
than hanging until stage 0's sleep finishes.
2305+
"""
2306+
start = time.monotonic()
2307+
with self.assertRaises(NONEXISTING_ERRORS):
2308+
subprocess.run_pipeline(
2309+
[sys.executable, '-c', 'import time; time.sleep(60)'],
2310+
NONEXISTING_CMD,
2311+
capture_output=True,
2312+
)
2313+
elapsed = time.monotonic() - start
2314+
self.assertLess(elapsed, 30,
2315+
"run_pipeline did not promptly clean up the running first "
2316+
"stage after the second stage failed to spawn")
2317+
22872318
def test_pipeline_explicit_stdout_pipe(self):
22882319
"""Test pipeline with explicit stdout=PIPE"""
22892320
result = subprocess.run_pipeline(

0 commit comments

Comments
 (0)