[Lldb-commits] [lldb] 8160276 - [lldb-dap] Synchronously wait for breakpoints resolves in tests (#140470)
via lldb-commits
lldb-commits at lists.llvm.org
Sat May 31 07:59:50 PDT 2025
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
- at 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
- at 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()
More information about the lldb-commits
mailing list