From 43244a8ae6d2a1367a2dab6edcd75bad805ded2d Mon Sep 17 00:00:00 2001 From: Benjamin Drung Date: Mon, 24 Mar 2025 16:30:11 +0100 Subject: [PATCH] test: add expected_status to wait_for_gdb_child_process Rename the helper method `wait_for_gdb_sleeping_child_process` to `wait_for_gdb_child_process` and allow specifying the expected status instead of hard-coding searching for the `sleep` state. Also query the GDB child processes recursively. This change allows detecting processes that kill themselves. --- tests/integration/test_signal_crashes.py | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/integration/test_signal_crashes.py b/tests/integration/test_signal_crashes.py index 70387884f..c7c8dc3a9 100644 --- a/tests/integration/test_signal_crashes.py +++ b/tests/integration/test_signal_crashes.py @@ -1190,7 +1190,7 @@ def do_crash( raise try: - command_process = self.wait_for_gdb_sleeping_child_process( + command_process = self.wait_for_gdb_child_process( gdb.pid, expected_command or command ) @@ -1369,17 +1369,17 @@ def test_wait_for_core_file_timeout( # False positive return statement for unittest.TestCase.fail # See https://github.com/pylint-dev/pylint/issues/4167 # pylint: disable-next=inconsistent-return-statements - def wait_for_gdb_sleeping_child_process( - self, gdb_pid: int, command: str + def wait_for_gdb_child_process( + self, gdb_pid: int, command: str, expected_status: str = "sleeping" ) -> psutil.Process: """Wait until GDB execv()ed the child process.""" gdb_process = psutil.Process(gdb_pid) timeout = 0.0 while timeout < 5: - gdb_children = gdb_process.children() + gdb_children = gdb_process.children(recursive=True) for process in gdb_children: try: - if process.status() != "sleeping": + if process.status() != expected_status: continue cmdline = process.cmdline() except psutil.NoSuchProcess: # pragma: no cover @@ -1391,13 +1391,13 @@ def wait_for_gdb_sleeping_child_process( timeout += 0.1 self.fail( - f"GDB child process {command} not started within " - f"{int(timeout)} seconds. GDB children: {gdb_children!r}" + f"GDB child process {command} with status {expected_status!r} not started" + f" within {int(timeout)} seconds. GDB children: {gdb_children!r}" ) @unittest.mock.patch("time.sleep") - def test_wait_for_gdb_sleeping_child_process(self, sleep_mock: MagicMock) -> None: - """Test wait_for_gdb_sleeping_child_process() helper method.""" + def test_wait_for_gdb_child_process(self, sleep_mock: MagicMock) -> None: + """Test wait_for_gdb_child_process() helper method.""" child = MagicMock(spec=psutil.Process) child.status.side_effect = [ "tracing-stop", # child not yet started @@ -1413,7 +1413,7 @@ def test_wait_for_gdb_sleeping_child_process(self, sleep_mock: MagicMock) -> Non [child], # child ready ] - self.wait_for_gdb_sleeping_child_process(123456789, self.TEST_EXECUTABLE) + self.wait_for_gdb_child_process(123456789, self.TEST_EXECUTABLE) sleep_mock.assert_called_with(0.1) self.assertEqual(sleep_mock.call_count, 3) @@ -1422,13 +1422,13 @@ def test_wait_for_gdb_sleeping_child_process(self, sleep_mock: MagicMock) -> Non @unittest.mock.patch("psutil.Process", spec=psutil.Process) @unittest.mock.patch("time.sleep") - def test_wait_for_gdb_sleeping_child_process_timeout( + def test_wait_for_gdb_child_process_timeout( self, sleep_mock: MagicMock, process_mock: MagicMock ) -> None: - """Test wait_for_gdb_sleeping_child_process() helper runs into timeout.""" + """Test wait_for_gdb_child_process() helper runs into timeout.""" process_mock.return_value.children.return_value = [] with unittest.mock.patch.object(self, "fail") as fail_mock: - self.wait_for_gdb_sleeping_child_process(123456789, self.TEST_EXECUTABLE) + self.wait_for_gdb_child_process(123456789, self.TEST_EXECUTABLE) fail_mock.assert_called_once() sleep_mock.assert_called_with(0.1) self.assertEqual(sleep_mock.call_count, 51)