https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/140470
>From 542fd2a828a2ed64b23b91c84e444f56e650ad20 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 18 May 2025 20:56:47 +0200 Subject: [PATCH 1/2] [lldb-dap] Attempt to synchronously wait for breakpoints resolve in lldb-dap tests in order to stabilize the tests --- .../test/tools/lldb-dap/dap_server.py | 6 +++-- .../test/tools/lldb-dap/lldbdap_testcase.py | 26 +++++++++++++++++-- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - .../tools/lldb-dap/module/TestDAP_module.py | 4 ++- .../TestDAP_terminatedEvent.py | 6 +++-- ...TestGetTargetBreakpointsRequestHandler.cpp | 10 +++++-- 7 files changed, 43 insertions(+), 11 deletions(-) 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 70fd0b0c419db..1b63ec77abba6 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 @@ -1187,7 +1187,7 @@ def request_locations(self, locationReference): } return self.send_recv(command_dict) - def request_testGetTargetBreakpoints(self): + def request_testGetTargetBreakpoints(self, only_resolved=False): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the target. @@ -1195,7 +1195,9 @@ def request_testGetTargetBreakpoints(self): command_dict = { "command": "_testGetTargetBreakpoints", "type": "request", - "arguments": {}, + "arguments": { + "onlyResolved": only_resolved, + }, } return self.send_recv(command_dict) 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 afdc746ed0d0d..cc45811bd5f27 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 @@ -48,7 +48,7 @@ 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. @@ -62,9 +62,11 @@ 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, timeout=10) 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. @@ -78,7 +80,27 @@ 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, timeout=10) return breakpoint_ids + + def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + unresolved_breakpoints = set(breakpoint_ids) + + # Check already resolved breakpoints + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + for resolved_breakpoint in resolved_breakpoints: + unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) + + while len(unresolved_breakpoints) > 0: + breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + if breakpoint_event is None: + break + + if breakpoint_event["body"]["reason"] in ["changed", "new"]: + unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + + 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): 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 aae1251b17c93..26df2573555df 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..2cea2a94adbbd 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,9 @@ 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..a93a4a2fa77cb 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,12 @@ 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() diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp index 5f4f016f6a1ef..129eb31b8356b 100644 --- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp @@ -15,12 +15,18 @@ namespace lldb_dap { void TestGetTargetBreakpointsRequestHandler::operator()( const llvm::json::Object &request) const { + const auto *arguments = request.getObject("arguments"); + bool only_resolved = GetBoolean(arguments, "onlyResolved").value_or(false); + llvm::json::Object response; FillResponse(request, response); llvm::json::Array response_breakpoints; for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { - auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); - response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + const auto target_bp = dap.target.GetBreakpointAtIndex(i); + if (!only_resolved || target_bp.GetNumResolvedLocations() > 0) { + auto bp = Breakpoint(dap, target_bp); + response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + } } llvm::json::Object body; body.try_emplace("breakpoints", std::move(response_breakpoints)); >From 3f08a3613c526a83db69b50069881d6f2815e210 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 18 May 2025 21:11:25 +0200 Subject: [PATCH 2/2] python format --- .../test/tools/lldb-dap/lldbdap_testcase.py | 34 ++++++++++++++----- .../tools/lldb-dap/module/TestDAP_module.py | 6 ++-- .../TestDAP_terminatedEvent.py | 12 +++++-- 3 files changed, 38 insertions(+), 14 deletions(-) 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 cc45811bd5f27..0da89b0a219f1 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 @@ -48,7 +48,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, wait_for_resolve=True): + 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. @@ -66,7 +68,9 @@ def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): + 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. @@ -83,24 +87,36 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None, if wait_for_resolve: self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - - def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + + def wait_for_breakpoints_to_resolve( + self, breakpoint_ids: list[str], timeout: Optional[float] = None + ): unresolved_breakpoints = set(breakpoint_ids) - + # Check already resolved breakpoints - resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints( + only_resolved=True + )["body"]["breakpoints"] for resolved_breakpoint in resolved_breakpoints: unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) while len(unresolved_breakpoints) > 0: - breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + breakpoint_event = self.dap_server.wait_for_event( + "breakpoint", timeout=timeout + ) if breakpoint_event is None: break if breakpoint_event["body"]["reason"] in ["changed", "new"]: - unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + unresolved_breakpoints.discard( + str(breakpoint_event["body"]["breakpoint"]["id"]) + ) - self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") + 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): 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 2cea2a94adbbd..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,9 +16,11 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + 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 a93a4a2fa77cb..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,12 +35,18 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + 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], wait_for_resolve=False)) + 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