]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-150966: Fix live profiling error tests (GH-151020)
authorPablo Galindo Salgado <Pablogsal@gmail.com>
Wed, 17 Jun 2026 13:17:16 +0000 (14:17 +0100)
committerGitHub <noreply@github.com>
Wed, 17 Jun 2026 13:17:16 +0000 (15:17 +0200)
Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py
Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst [new file with mode: 0644]

index 59373a8d00c03cf1d8d1826dc21cfc777960a8f3..ae4ee969f34d8b3ad7b7e75368e6acbfdaa24c82 100644 (file)
@@ -825,17 +825,34 @@ class TestLiveCollectorWithMockDisplayHelpers(unittest.TestCase):
 class TestLiveModeErrors(unittest.TestCase):
     """Tests running error commands in the live mode fails gracefully."""
 
+    class QuitWhenFinishedDisplay(MockDisplay):
+        def __init__(self, collector):
+            super().__init__()
+            self.collector = collector
+
+        def get_input(self):
+            ch = super().get_input()
+            if ch != -1:
+                return ch
+            # Sampling only stops once the target process has exited, at
+            # which point the collector is marked finished. Quit then so the
+            # run can surface the target's stderr. We must not rely on the
+            # target's pid still being signalable: once it exits it lingers
+            # as a zombie (it is reaped after sample_live returns), so a
+            # liveness check would never observe it gone and would hang.
+            if self.collector.finished:
+                return ord('q')
+            return -1
+
     def mock_curses_wrapper(self, func):
         func(mock.MagicMock())
 
     def mock_init_curses_side_effect(self, n_times, mock_self, stdscr):
-        mock_self.display = MockDisplay()
-        # Allow the loop to run for a bit (approx 0.5s) before quitting
-        # This ensures we don't exit too early while the subprocess is
-        # still failing
+        mock_self.display = self.QuitWhenFinishedDisplay(mock_self)
+        # Feed non-input events so live mode keeps polling while the target
+        # process is still running; once it exits the display quits on its own.
         for _ in range(n_times):
             mock_self.display.simulate_input(-1)
-        mock_self.display.simulate_input(ord('q'))
 
     def test_run_failed_module_live(self):
         """Test that running a existing module that fails exits with clean error."""
diff --git a/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst
new file mode 100644 (file)
index 0000000..3bbb471
--- /dev/null
@@ -0,0 +1,2 @@
+Avoid prematurely terminating failing live sampling profiler test targets,
+which made stderr assertions flaky on ASAN buildbots.