1""" 2Test lldb-dap runInTerminal reverse request 3""" 4 5 6import dap_server 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10import lldbdap_testcase 11import time 12import os 13import subprocess 14import shutil 15import json 16from threading import Thread 17 18 19class TestDAP_runInTerminal(lldbdap_testcase.DAPTestCaseBase): 20 def readPidMessage(self, fifo_file): 21 with open(fifo_file, "r") as file: 22 self.assertIn("pid", file.readline()) 23 24 def sendDidAttachMessage(self, fifo_file): 25 with open(fifo_file, "w") as file: 26 file.write(json.dumps({"kind": "didAttach"}) + "\n") 27 28 def readErrorMessage(self, fifo_file): 29 with open(fifo_file, "r") as file: 30 return file.readline() 31 32 def isTestSupported(self): 33 # For some strange reason, this test fails on python3.6 34 if not (sys.version_info.major == 3 and sys.version_info.minor >= 7): 35 return False 36 try: 37 # We skip this test for debug builds because it takes too long parsing lldb's own 38 # debug info. Release builds are fine. 39 # Checking the size of the lldb-dap binary seems to be a decent proxy for a quick 40 # detection. It should be far less than 1 MB in Release builds. 41 if os.path.getsize(os.environ["LLDBDAP_EXEC"]) < 1000000: 42 return True 43 except: 44 return False 45 46 @skipIfWindows 47 @skipIf(archs=no_match(["x86_64"])) 48 def test_runInTerminal(self): 49 if not self.isTestSupported(): 50 return 51 """ 52 Tests the "runInTerminal" reverse request. It makes sure that the IDE can 53 launch the inferior with the correct environment variables and arguments. 54 """ 55 program = self.getBuildArtifact("a.out") 56 source = "main.c" 57 self.build_and_launch( 58 program, runInTerminal=True, args=["foobar"], env=["FOO=bar"] 59 ) 60 61 self.assertEqual( 62 len(self.dap_server.reverse_requests), 63 1, 64 "make sure we got a reverse request", 65 ) 66 67 request = self.dap_server.reverse_requests[0] 68 self.assertIn(self.lldbDAPExec, request["arguments"]["args"]) 69 self.assertIn(program, request["arguments"]["args"]) 70 self.assertIn("foobar", request["arguments"]["args"]) 71 self.assertIn("FOO", request["arguments"]["env"]) 72 73 breakpoint_line = line_number(source, "// breakpoint") 74 75 self.set_source_breakpoints(source, [breakpoint_line]) 76 self.continue_to_next_stop() 77 78 # We verify we actually stopped inside the loop 79 counter = int(self.dap_server.get_local_variable_value("counter")) 80 self.assertGreater(counter, 0) 81 82 # We verify we were able to set the launch arguments 83 argc = int(self.dap_server.get_local_variable_value("argc")) 84 self.assertEqual(argc, 2) 85 86 argv1 = self.dap_server.request_evaluate("argv[1]")["body"]["result"] 87 self.assertIn("foobar", argv1) 88 89 # We verify we were able to set the environment 90 env = self.dap_server.request_evaluate("foo")["body"]["result"] 91 self.assertIn("bar", env) 92 93 @skipIf(archs=no_match(["x86_64"])) 94 def test_runInTerminalWithObjectEnv(self): 95 if not self.isTestSupported(): 96 return 97 """ 98 Tests the "runInTerminal" reverse request. It makes sure that the IDE can 99 launch the inferior with the correct environment variables using an object. 100 """ 101 program = self.getBuildArtifact("a.out") 102 self.build_and_launch(program, runInTerminal=True, env={"FOO": "BAR"}) 103 104 self.assertEqual( 105 len(self.dap_server.reverse_requests), 106 1, 107 "make sure we got a reverse request", 108 ) 109 110 request = self.dap_server.reverse_requests[0] 111 request_envs = request["arguments"]["env"] 112 113 self.assertIn("FOO", request_envs) 114 self.assertEqual("BAR", request_envs["FOO"]) 115 116 @skipIfWindows 117 @skipIf(archs=no_match(["x86_64"])) 118 def test_runInTerminalInvalidTarget(self): 119 if not self.isTestSupported(): 120 return 121 self.build_and_create_debug_adaptor() 122 response = self.launch( 123 "INVALIDPROGRAM", 124 runInTerminal=True, 125 args=["foobar"], 126 env=["FOO=bar"], 127 expectFailure=True, 128 ) 129 self.assertFalse(response["success"]) 130 self.assertIn( 131 "Could not create a target for a program 'INVALIDPROGRAM': 'INVALIDPROGRAM' does not exist", 132 response["message"], 133 ) 134 135 @skipIfWindows 136 @skipIf(archs=no_match(["x86_64"])) 137 def test_missingArgInRunInTerminalLauncher(self): 138 if not self.isTestSupported(): 139 return 140 proc = subprocess.run( 141 [self.lldbDAPExec, "--launch-target", "INVALIDPROGRAM"], 142 capture_output=True, 143 universal_newlines=True, 144 ) 145 self.assertNotEqual(proc.returncode, 0) 146 self.assertIn( 147 '"--launch-target" requires "--comm-file" to be specified', proc.stderr 148 ) 149 150 @skipIfWindows 151 @skipIf(archs=no_match(["x86_64"])) 152 def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self): 153 if not self.isTestSupported(): 154 return 155 comm_file = os.path.join(self.getBuildDir(), "comm-file") 156 os.mkfifo(comm_file) 157 158 proc = subprocess.Popen( 159 [ 160 self.lldbDAPExec, 161 "--comm-file", 162 comm_file, 163 "--launch-target", 164 "INVALIDPROGRAM", 165 ], 166 universal_newlines=True, 167 stderr=subprocess.PIPE, 168 ) 169 170 self.readPidMessage(comm_file) 171 self.sendDidAttachMessage(comm_file) 172 self.assertIn("No such file or directory", self.readErrorMessage(comm_file)) 173 174 _, stderr = proc.communicate() 175 self.assertIn("No such file or directory", stderr) 176 177 @skipIfWindows 178 @skipIf(archs=no_match(["x86_64"])) 179 def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self): 180 if not self.isTestSupported(): 181 return 182 comm_file = os.path.join(self.getBuildDir(), "comm-file") 183 os.mkfifo(comm_file) 184 185 proc = subprocess.Popen( 186 [ 187 self.lldbDAPExec, 188 "--comm-file", 189 comm_file, 190 "--launch-target", 191 "echo", 192 "foo", 193 ], 194 universal_newlines=True, 195 stdout=subprocess.PIPE, 196 ) 197 198 self.readPidMessage(comm_file) 199 self.sendDidAttachMessage(comm_file) 200 201 stdout, _ = proc.communicate() 202 self.assertIn("foo", stdout) 203 204 @skipIfWindows 205 @skipIf(archs=no_match(["x86_64"])) 206 def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self): 207 if not self.isTestSupported(): 208 return 209 comm_file = os.path.join(self.getBuildDir(), "comm-file") 210 os.mkfifo(comm_file) 211 212 proc = subprocess.Popen( 213 [self.lldbDAPExec, "--comm-file", comm_file, "--launch-target", "env"], 214 universal_newlines=True, 215 stdout=subprocess.PIPE, 216 env={**os.environ, "FOO": "BAR"}, 217 ) 218 219 self.readPidMessage(comm_file) 220 self.sendDidAttachMessage(comm_file) 221 222 stdout, _ = proc.communicate() 223 self.assertIn("FOO=BAR", stdout) 224 225 @skipIfWindows 226 @skipIf(archs=no_match(["x86_64"])) 227 def test_NonAttachedRunInTerminalLauncher(self): 228 if not self.isTestSupported(): 229 return 230 comm_file = os.path.join(self.getBuildDir(), "comm-file") 231 os.mkfifo(comm_file) 232 233 proc = subprocess.Popen( 234 [ 235 self.lldbDAPExec, 236 "--comm-file", 237 comm_file, 238 "--launch-target", 239 "echo", 240 "foo", 241 ], 242 universal_newlines=True, 243 stderr=subprocess.PIPE, 244 env={**os.environ, "LLDB_DAP_RIT_TIMEOUT_IN_MS": "1000"}, 245 ) 246 247 self.readPidMessage(comm_file) 248 249 _, stderr = proc.communicate() 250 self.assertIn("Timed out trying to get messages from the debug adaptor", stderr) 251