1132e57bcSWalter Erquinigo"""
2132e57bcSWalter ErquinigoTest lldb-vscode runInTerminal reverse request
3132e57bcSWalter Erquinigo"""
4132e57bcSWalter Erquinigo
5132e57bcSWalter Erquinigo
6132e57bcSWalter Erquinigoimport unittest2
7132e57bcSWalter Erquinigoimport vscode
8132e57bcSWalter Erquinigofrom lldbsuite.test.decorators import *
9132e57bcSWalter Erquinigofrom lldbsuite.test.lldbtest import *
10132e57bcSWalter Erquinigofrom lldbsuite.test import lldbutil
11132e57bcSWalter Erquinigoimport lldbvscode_testcase
12132e57bcSWalter Erquinigoimport time
13132e57bcSWalter Erquinigoimport os
140f0462caSWalter Erquinigoimport subprocess
150f0462caSWalter Erquinigoimport shutil
160f0462caSWalter Erquinigoimport json
170f0462caSWalter Erquinigofrom threading import Thread
18132e57bcSWalter Erquinigo
19132e57bcSWalter Erquinigo
20132e57bcSWalter Erquinigoclass TestVSCode_runInTerminal(lldbvscode_testcase.VSCodeTestCaseBase):
21132e57bcSWalter Erquinigo
220f0462caSWalter Erquinigo    def readPidMessage(self, fifo_file):
230f0462caSWalter Erquinigo        with open(fifo_file, "r") as file:
240f0462caSWalter Erquinigo            self.assertIn("pid", file.readline())
250f0462caSWalter Erquinigo
260f0462caSWalter Erquinigo    def sendDidAttachMessage(self, fifo_file):
270f0462caSWalter Erquinigo        with open(fifo_file, "w") as file:
280f0462caSWalter Erquinigo            file.write(json.dumps({"kind": "didAttach"}) + "\n")
290f0462caSWalter Erquinigo
300f0462caSWalter Erquinigo    def readErrorMessage(self, fifo_file):
310f0462caSWalter Erquinigo        with open(fifo_file, "r") as file:
320f0462caSWalter Erquinigo            return file.readline()
330f0462caSWalter Erquinigo
34*ab5591e1SWalter Erquinigo    def isTestSupported(self):
35*ab5591e1SWalter Erquinigo        # For some strange reason, this test fails on python3.6
36*ab5591e1SWalter Erquinigo        if not (sys.version_info.major == 3 and sys.version_info.minor >= 7):
37*ab5591e1SWalter Erquinigo            return False
38*ab5591e1SWalter Erquinigo        try:
39*ab5591e1SWalter Erquinigo            # We skip this test for debug builds because it takes too long parsing lldb's own
40*ab5591e1SWalter Erquinigo            # debug info. Release builds are fine.
41*ab5591e1SWalter Erquinigo            # Checking the size of the lldb-vscode binary seems to be a decent proxy for a quick
42*ab5591e1SWalter Erquinigo            # detection. It should be far less than 1 MB in Release builds.
43*ab5591e1SWalter Erquinigo            if os.path.getsize(os.environ["LLDBVSCODE_EXEC"]) < 1000000:
44*ab5591e1SWalter Erquinigo                return True
45*ab5591e1SWalter Erquinigo        except:
46*ab5591e1SWalter Erquinigo            return False
47*ab5591e1SWalter Erquinigo
480f0462caSWalter Erquinigo    @skipIfWindows
49132e57bcSWalter Erquinigo    @skipIfRemote
5012049d88SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
51132e57bcSWalter Erquinigo    def test_runInTerminal(self):
52*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
53*ab5591e1SWalter Erquinigo            return
54132e57bcSWalter Erquinigo        '''
55132e57bcSWalter Erquinigo            Tests the "runInTerminal" reverse request. It makes sure that the IDE can
56132e57bcSWalter Erquinigo            launch the inferior with the correct environment variables and arguments.
57132e57bcSWalter Erquinigo        '''
58132e57bcSWalter Erquinigo        program = self.getBuildArtifact("a.out")
59132e57bcSWalter Erquinigo        source = 'main.c'
600f0462caSWalter Erquinigo        self.build_and_launch(
610f0462caSWalter Erquinigo            program, stopOnEntry=True, runInTerminal=True, args=["foobar"],
620f0462caSWalter Erquinigo            env=["FOO=bar"])
630f0462caSWalter Erquinigo
64132e57bcSWalter Erquinigo        breakpoint_line = line_number(source, '// breakpoint')
65132e57bcSWalter Erquinigo
66132e57bcSWalter Erquinigo        self.set_source_breakpoints(source, [breakpoint_line])
67132e57bcSWalter Erquinigo        self.continue_to_next_stop()
68132e57bcSWalter Erquinigo
69132e57bcSWalter Erquinigo        # We verify we actually stopped inside the loop
70132e57bcSWalter Erquinigo        counter = int(self.vscode.get_local_variable_value('counter'))
71132e57bcSWalter Erquinigo        self.assertTrue(counter > 0)
72132e57bcSWalter Erquinigo
73132e57bcSWalter Erquinigo        # We verify we were able to set the launch arguments
74132e57bcSWalter Erquinigo        argc = int(self.vscode.get_local_variable_value('argc'))
75132e57bcSWalter Erquinigo        self.assertEqual(argc, 2)
76132e57bcSWalter Erquinigo
77132e57bcSWalter Erquinigo        argv1 = self.vscode.request_evaluate('argv[1]')['body']['result']
78132e57bcSWalter Erquinigo        self.assertIn('foobar', argv1)
79132e57bcSWalter Erquinigo
80132e57bcSWalter Erquinigo        # We verify we were able to set the environment
81132e57bcSWalter Erquinigo        env = self.vscode.request_evaluate('foo')['body']['result']
82132e57bcSWalter Erquinigo        self.assertIn('bar', env)
830f0462caSWalter Erquinigo
840f0462caSWalter Erquinigo    @skipIfWindows
850f0462caSWalter Erquinigo    @skipIfRemote
8650337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
870f0462caSWalter Erquinigo    def test_runInTerminalInvalidTarget(self):
88*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
89*ab5591e1SWalter Erquinigo            return
900f0462caSWalter Erquinigo        self.build_and_create_debug_adaptor()
910f0462caSWalter Erquinigo        response = self.launch(
920f0462caSWalter Erquinigo            "INVALIDPROGRAM", stopOnEntry=True, runInTerminal=True, args=["foobar"], env=["FOO=bar"], expectFailure=True)
930f0462caSWalter Erquinigo        self.assertFalse(response['success'])
940f0462caSWalter Erquinigo        self.assertIn("Could not create a target for a program 'INVALIDPROGRAM': unable to find executable",
950f0462caSWalter Erquinigo            response['message'])
960f0462caSWalter Erquinigo
970f0462caSWalter Erquinigo    @skipIfWindows
980f0462caSWalter Erquinigo    @skipIfRemote
9950337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
1000f0462caSWalter Erquinigo    def test_missingArgInRunInTerminalLauncher(self):
101*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
102*ab5591e1SWalter Erquinigo            return
1030f0462caSWalter Erquinigo        proc = subprocess.run([self.lldbVSCodeExec,  "--launch-target", "INVALIDPROGRAM"],
1040f0462caSWalter Erquinigo            capture_output=True, universal_newlines=True)
1050f0462caSWalter Erquinigo        self.assertTrue(proc.returncode != 0)
1060f0462caSWalter Erquinigo        self.assertIn('"--launch-target" requires "--comm-file" to be specified', proc.stderr)
1070f0462caSWalter Erquinigo
1080f0462caSWalter Erquinigo    @skipIfWindows
1090f0462caSWalter Erquinigo    @skipIfRemote
11050337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
1110f0462caSWalter Erquinigo    def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self):
112*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
113*ab5591e1SWalter Erquinigo            return
1140f0462caSWalter Erquinigo        comm_file = os.path.join(self.getBuildDir(), "comm-file")
1150f0462caSWalter Erquinigo        os.mkfifo(comm_file)
1160f0462caSWalter Erquinigo
1170f0462caSWalter Erquinigo        proc = subprocess.Popen(
1180f0462caSWalter Erquinigo            [self.lldbVSCodeExec, "--comm-file", comm_file, "--launch-target", "INVALIDPROGRAM"],
1190f0462caSWalter Erquinigo            universal_newlines=True, stderr=subprocess.PIPE)
1200f0462caSWalter Erquinigo
1210f0462caSWalter Erquinigo        self.readPidMessage(comm_file)
1220f0462caSWalter Erquinigo        self.sendDidAttachMessage(comm_file)
1230f0462caSWalter Erquinigo        self.assertIn("No such file or directory", self.readErrorMessage(comm_file))
1240f0462caSWalter Erquinigo
1250f0462caSWalter Erquinigo        _, stderr = proc.communicate()
1260f0462caSWalter Erquinigo        self.assertIn("No such file or directory", stderr)
1270f0462caSWalter Erquinigo
1280f0462caSWalter Erquinigo    @skipIfWindows
1290f0462caSWalter Erquinigo    @skipIfRemote
13050337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
1310f0462caSWalter Erquinigo    def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self):
132*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
133*ab5591e1SWalter Erquinigo            return
1340f0462caSWalter Erquinigo        comm_file = os.path.join(self.getBuildDir(), "comm-file")
1350f0462caSWalter Erquinigo        os.mkfifo(comm_file)
1360f0462caSWalter Erquinigo
1370f0462caSWalter Erquinigo        proc = subprocess.Popen(
1380f0462caSWalter Erquinigo            [self.lldbVSCodeExec, "--comm-file", comm_file, "--launch-target", "echo", "foo"],
1390f0462caSWalter Erquinigo            universal_newlines=True, stdout=subprocess.PIPE)
1400f0462caSWalter Erquinigo
1410f0462caSWalter Erquinigo        self.readPidMessage(comm_file)
1420f0462caSWalter Erquinigo        self.sendDidAttachMessage(comm_file)
1430f0462caSWalter Erquinigo
1440f0462caSWalter Erquinigo        stdout, _ = proc.communicate()
1450f0462caSWalter Erquinigo        self.assertIn("foo", stdout)
1460f0462caSWalter Erquinigo
1470f0462caSWalter Erquinigo    @skipIfWindows
1480f0462caSWalter Erquinigo    @skipIfRemote
14950337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
1500f0462caSWalter Erquinigo    def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self):
151*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
152*ab5591e1SWalter Erquinigo            return
1530f0462caSWalter Erquinigo        comm_file = os.path.join(self.getBuildDir(), "comm-file")
1540f0462caSWalter Erquinigo        os.mkfifo(comm_file)
1550f0462caSWalter Erquinigo
1560f0462caSWalter Erquinigo        proc = subprocess.Popen(
1570f0462caSWalter Erquinigo            [self.lldbVSCodeExec, "--comm-file", comm_file, "--launch-target", "env"],
1580f0462caSWalter Erquinigo            universal_newlines=True, stdout=subprocess.PIPE,
1590f0462caSWalter Erquinigo            env={**os.environ, "FOO": "BAR"})
1600f0462caSWalter Erquinigo
1610f0462caSWalter Erquinigo        self.readPidMessage(comm_file)
1620f0462caSWalter Erquinigo        self.sendDidAttachMessage(comm_file)
1630f0462caSWalter Erquinigo
1640f0462caSWalter Erquinigo        stdout, _ = proc.communicate()
1650f0462caSWalter Erquinigo        self.assertIn("FOO=BAR", stdout)
1660f0462caSWalter Erquinigo
1670f0462caSWalter Erquinigo    @skipIfWindows
1680f0462caSWalter Erquinigo    @skipIfRemote
16950337fb9SWalter Erquinigo    @skipIf(archs=no_match(['x86_64']))
1700f0462caSWalter Erquinigo    def test_NonAttachedRunInTerminalLauncher(self):
171*ab5591e1SWalter Erquinigo        if not self.isTestSupported():
172*ab5591e1SWalter Erquinigo            return
1730f0462caSWalter Erquinigo        comm_file = os.path.join(self.getBuildDir(), "comm-file")
1740f0462caSWalter Erquinigo        os.mkfifo(comm_file)
1750f0462caSWalter Erquinigo
1760f0462caSWalter Erquinigo        proc = subprocess.Popen(
1770f0462caSWalter Erquinigo            [self.lldbVSCodeExec, "--comm-file", comm_file, "--launch-target", "echo", "foo"],
1780f0462caSWalter Erquinigo            universal_newlines=True, stderr=subprocess.PIPE,
1790f0462caSWalter Erquinigo            env={**os.environ, "LLDB_VSCODE_RIT_TIMEOUT_IN_MS": "1000"})
1800f0462caSWalter Erquinigo
1810f0462caSWalter Erquinigo        self.readPidMessage(comm_file)
1820f0462caSWalter Erquinigo
1830f0462caSWalter Erquinigo        _, stderr = proc.communicate()
1840f0462caSWalter Erquinigo        self.assertIn("Timed out trying to get messages from the debug adaptor", stderr)
185