From 1011901528f1f3f2d51313227269d98cff1dac68 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Tue, 25 Aug 2026 13:41:23 +0200 Subject: [PATCH] tests: fix race in GdbController gcore tests The gcore tests wrote the "Saved corefile" and GCORE_MARKER reply lines into the pipe before calling generate_coredump(). If the reader thread consumed those lines before generate_coredump() reset _gcore_done and _last_corefile, the reset discarded them and the wait timed out, returning None (seen as a flaky CI failure on the Python 3.14 job). Feed the reply via a proc.stdin.write side effect triggered by the GCORE_MARKER echo command instead, so it arrives only after the controller has issued the gcore command -- mirroring real gdb and making the ordering deterministic. Signed-off-by: raiden00pl Assisted-by: Claude Code --- tests/debug/test_gdb_controller.py | 42 ++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/tests/debug/test_gdb_controller.py b/tests/debug/test_gdb_controller.py index 48eaf2f..0218fda 100644 --- a/tests/debug/test_gdb_controller.py +++ b/tests/debug/test_gdb_controller.py @@ -76,6 +76,24 @@ def _pipe_process() -> Tuple[MagicMock, BinaryIO]: return proc, w_file +def _respond_on_gcore( + proc: MagicMock, w_file: BinaryIO, response: bytes +) -> None: + """Feed *response* into the pipe when the gcore marker echo is sent. + + Replying only after GdbController has issued the command mirrors real + gdb and avoids racing generate_coredump()'s state reset: lines written + to the pipe before the call may be consumed by the reader thread and + then discarded by the reset, leaving the wait to time out. + """ + + def write(data: bytes) -> None: + if GdbController.GCORE_MARKER.encode() in data: + w_file.write(response) + + proc.stdin.write.side_effect = write + + @pytest.fixture def elf(tmp_path: "Path") -> "Path": p = tmp_path / "app.elf" @@ -468,8 +486,14 @@ def test_generate_coredump_returns_path_on_success( assert start_ok is True - w_file.write(f"Saved corefile {corefile}\n".encode()) - w_file.write(f"{GdbController.GCORE_MARKER}\n".encode()) + _respond_on_gcore( + proc, + w_file, + ( + f"Saved corefile {corefile}\n" + f"{GdbController.GCORE_MARKER}\n" + ).encode(), + ) result = ctrl.generate_coredump(tmp_path, "test", timeout=5.0) # Close write end → EOF → reader exits; join to avoid ResourceWarning w_file.close() @@ -489,8 +513,14 @@ def test_generate_coredump_returns_none_when_gcore_fails( w_file.write(b"(gdb) \n") ctrl.start(timeout=5.0) - w_file.write(b"Unable to fetch a corefile\n") - w_file.write(f"{GdbController.GCORE_MARKER}\n".encode()) + _respond_on_gcore( + proc, + w_file, + ( + "Unable to fetch a corefile\n" + f"{GdbController.GCORE_MARKER}\n" + ).encode(), + ) result = ctrl.generate_coredump(tmp_path, "test", timeout=5.0) w_file.close() ctrl.stop() @@ -553,7 +583,9 @@ def test_generate_coredump_uses_gcore_cmd( ctrl = GdbController(elf, _cfg(gcore_cmd="gcore -t nuttx")) w_file.write(b"(gdb) \n") ctrl.start(timeout=5.0) - w_file.write(f"{GdbController.GCORE_MARKER}\n".encode()) + _respond_on_gcore( + proc, w_file, f"{GdbController.GCORE_MARKER}\n".encode() + ) ctrl.generate_coredump(tmp_path, "t", timeout=5.0) w_file.close() ctrl.stop()