113 lines · python
1"""2Test lldb-dap attach request3"""4 5from lldbsuite.test.decorators import *6from lldbsuite.test.lldbtest import *7from lldbsuite.test import lldbutil8import lldbdap_testcase9import subprocess10import threading11import time12 13 14# Often fails on Arm Linux, but not specifically because it's Arm, something in15# process scheduling can cause a massive (minutes) delay during this test.16@skipIf(oslist=["linux"], archs=["arm$"])17class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase):18 def spawn(self, args):19 self.process = subprocess.Popen(20 args,21 stdin=subprocess.PIPE,22 stdout=subprocess.PIPE,23 stderr=subprocess.PIPE,24 universal_newlines=True,25 )26 27 def spawn_and_wait(self, program, delay):28 time.sleep(delay)29 self.spawn([program])30 self.process.wait()31 32 def continue_and_verify_pid(self):33 self.do_continue()34 out, _ = self.process.communicate("foo")35 self.assertIn(f"pid = {self.process.pid}", out)36 37 def test_by_pid(self):38 """39 Tests attaching to a process by process ID.40 """41 program = self.build_and_create_debug_adapter_for_attach()42 self.spawn([program])43 self.attach(pid=self.process.pid)44 self.continue_and_verify_pid()45 46 def test_by_name(self):47 """48 Tests attaching to a process by process name.49 """50 program = self.build_and_create_debug_adapter_for_attach()51 52 # Use a file as a synchronization point between test and inferior.53 pid_file_path = lldbutil.append_to_process_working_directory(54 self, "pid_file_%d" % (int(time.time()))55 )56 self.spawn([program, pid_file_path])57 lldbutil.wait_for_file_on_target(self, pid_file_path)58 59 self.attach(program=program)60 self.continue_and_verify_pid()61 62 def test_by_name_waitFor(self):63 """64 Tests waiting for, and attaching to a process by process name that65 doesn't exist yet.66 """67 program = self.build_and_create_debug_adapter_for_attach()68 self.spawn_thread = threading.Thread(69 target=self.spawn_and_wait,70 args=(71 program,72 1.0,73 ),74 )75 self.spawn_thread.start()76 self.attach(program=program, waitFor=True)77 self.continue_and_verify_pid()78 79 def test_attach_with_missing_debuggerId_or_targetId(self):80 """81 Test that attaching with only one of debuggerId/targetId specified82 fails with the expected error message.83 """84 self.build_and_create_debug_adapter()85 86 # Test with only targetId specified (no debuggerId)87 resp = self.attach(targetId=99999, expectFailure=True)88 self.assertFalse(resp["success"])89 self.assertIn(90 "Both debuggerId and targetId must be specified together",91 resp["body"]["error"]["format"],92 )93 94 def test_attach_with_invalid_debuggerId_and_targetId(self):95 """96 Test that attaching with both debuggerId and targetId specified but97 invalid fails with an appropriate error message.98 """99 self.build_and_create_debug_adapter()100 101 # Attach with both debuggerId=9999 and targetId=99999 (both invalid).102 # Since debugger ID 9999 likely doesn't exist in the global registry,103 # we expect a validation error.104 resp = self.attach(debuggerId=9999, targetId=99999, expectFailure=True)105 self.assertFalse(resp["success"])106 error_msg = resp["body"]["error"]["format"]107 # Either error is acceptable - both indicate the debugger reuse108 # validation is working correctly109 self.assertTrue(110 "Unable to find existing debugger" in error_msg111 or f"Expected debugger/target not found error, got: {error_msg}"112 )113