@@ -825,17 +825,34 @@ def test_get_all_lines_full_display(self):
825825class TestLiveModeErrors (unittest .TestCase ):
826826 """Tests running error commands in the live mode fails gracefully."""
827827
828+ class QuitWhenFinishedDisplay (MockDisplay ):
829+ def __init__ (self , collector ):
830+ super ().__init__ ()
831+ self .collector = collector
832+
833+ def get_input (self ):
834+ ch = super ().get_input ()
835+ if ch != - 1 :
836+ return ch
837+ # Sampling only stops once the target process has exited, at
838+ # which point the collector is marked finished. Quit then so the
839+ # run can surface the target's stderr. We must not rely on the
840+ # target's pid still being signalable: once it exits it lingers
841+ # as a zombie (it is reaped after sample_live returns), so a
842+ # liveness check would never observe it gone and would hang.
843+ if self .collector .finished :
844+ return ord ('q' )
845+ return - 1
846+
828847 def mock_curses_wrapper (self , func ):
829848 func (mock .MagicMock ())
830849
831850 def mock_init_curses_side_effect (self , n_times , mock_self , stdscr ):
832- mock_self .display = MockDisplay ()
833- # Allow the loop to run for a bit (approx 0.5s) before quitting
834- # This ensures we don't exit too early while the subprocess is
835- # still failing
851+ mock_self .display = self .QuitWhenFinishedDisplay (mock_self )
852+ # Feed non-input events so live mode keeps polling while the target
853+ # process is still running; once it exits the display quits on its own.
836854 for _ in range (n_times ):
837855 mock_self .display .simulate_input (- 1 )
838- mock_self .display .simulate_input (ord ('q' ))
839856
840857 def test_run_failed_module_live (self ):
841858 """Test that running a existing module that fails exits with clean error."""
0 commit comments