Author: Ely Ronnen Date: 2025-05-31T16:59:46+02:00 New Revision: 81602769d830e6791200e8cc7dd10a3afc32570b
URL: https://github.com/llvm/llvm-project/commit/81602769d830e6791200e8cc7dd10a3afc32570b DIFF: https://github.com/llvm/llvm-project/commit/81602769d830e6791200e8cc7dd10a3afc32570b.diff LOG: [lldb-dap] Synchronously wait for breakpoints resolves in tests (#140470) Attempt to improve tests by synchronously waiting for breakpoints to resolve. Not sure if it will fix all the tests but I think it should make the tests more stable Added: Modified: lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py lldb/test/API/tools/lldb-dap/module/TestDAP_module.py lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py Removed: ################################################################################ diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 4c8c51905e1d0..6b41aef2bb5b8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -166,6 +166,7 @@ def __init__( self.initialized = False self.frame_scopes = {} self.init_commands = init_commands + self.resolved_breakpoints = {} @classmethod def encode_content(cls, s: str) -> bytes: @@ -296,6 +297,9 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: # and 'progressEnd' events. Keep these around in case test # cases want to verify them. self.progress_events.append(packet) + elif event == "breakpoint": + # Breakpoint events are sent when a breakpoint is resolved + self._update_verified_breakpoints([body["breakpoint"]]) elif packet_type == "response": if packet["command"] == "disconnect": @@ -309,6 +313,13 @@ def _process_continued(self, all_threads_continued: bool): if all_threads_continued: self.thread_stop_reasons = {} + def _update_verified_breakpoints(self, breakpoints: list[Event]): + for breakpoint in breakpoints: + if "id" in breakpoint: + self.resolved_breakpoints[str(breakpoint["id"])] = breakpoint.get( + "verified", False + ) + def send_packet(self, command_dict: Request, set_sequence=True): """Take the "command_dict" python dictionary and encode it as a JSON string and send the contents as a packet to the VSCode debug @@ -454,6 +465,17 @@ def wait_for_breakpoint_events(self, timeout: Optional[float] = None): breakpoint_events.append(event) return breakpoint_events + def wait_for_breakpoints_to_be_verified( + self, breakpoint_ids: list[str], timeout: Optional[float] = None + ): + """Wait for all breakpoints to be verified. Return all unverified breakpoints.""" + while any(id not in self.resolved_breakpoints for id in breakpoint_ids): + breakpoint_event = self.wait_for_event("breakpoint", timeout=timeout) + if breakpoint_event is None: + break + + return [id for id in breakpoint_ids if id not in self.resolved_breakpoints] + def wait_for_exited(self, timeout: Optional[float] = None): event_dict = self.wait_for_event("exited", timeout=timeout) if event_dict is None: @@ -1013,7 +1035,10 @@ def request_setBreakpoints(self, source: Source, line_array, data=None): "type": "request", "arguments": args_dict, } - return self.send_recv(command_dict) + response = self.send_recv(command_dict) + if response["success"]: + self._update_verified_breakpoints(response["body"]["breakpoints"]) + return response def request_setExceptionBreakpoints(self, filters): args_dict = {"filters": filters} @@ -1039,7 +1064,10 @@ def request_setFunctionBreakpoints(self, names, condition=None, hitCondition=Non "type": "request", "arguments": args_dict, } - return self.send_recv(command_dict) + response = self.send_recv(command_dict) + if response["success"]: + self._update_verified_breakpoints(response["body"]["breakpoints"]) + return response def request_dataBreakpointInfo( self, variablesReference, name, frameIndex=0, threadId=None diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 91ae55977046b..e26dbf6ae514f 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -49,7 +49,9 @@ def build_and_create_debug_adapter_for_attach(self): self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None): + def set_source_breakpoints( + self, source_path, lines, data=None, wait_for_resolve=True + ): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. @@ -65,9 +67,13 @@ def set_source_breakpoints(self, source_path, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids) return breakpoint_ids - def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + def set_source_breakpoints_assembly( + self, source_reference, lines, data=None, wait_for_resolve=True + ): response = self.dap_server.request_setBreakpoints( Source(source_reference=source_reference), lines, @@ -79,9 +85,13 @@ def set_source_breakpoints_assembly(self, source_reference, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None): + def set_function_breakpoints( + self, functions, condition=None, hitCondition=None, wait_for_resolve=True + ): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. @@ -95,8 +105,22 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids) return breakpoint_ids + def wait_for_breakpoints_to_resolve( + self, breakpoint_ids: list[str], timeout: Optional[float] = DEFAULT_TIMEOUT + ): + unresolved_breakpoints = self.dap_server.wait_for_breakpoints_to_be_verified( + breakpoint_ids, timeout + ) + self.assertEqual( + len(unresolved_breakpoints), + 0, + f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}", + ) + def waitUntil(self, condition_callback): for _ in range(20): if condition_callback(): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 22470daac2887..831edd6494c1e 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os -@skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase -@skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 3fc0f752ee39e..4fc221668a8ee 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -16,7 +16,11 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() diff --git a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py index b0abe2a38dac4..7de85bd1589cd 100644 --- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py @@ -35,10 +35,18 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") - breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line])) + breakpoint_ids.append( + self.set_source_breakpoints( + "main.cpp", [main_bp_line], wait_for_resolve=False + ) + ) self.continue_to_breakpoints(breakpoint_ids) self.continue_to_exit() _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits