1from __future__ import absolute_import 2import os 3import tempfile 4import subprocess 5import sys 6 7import lit.Test 8import lit.TestRunner 9import lit.util 10from lit.formats.base import TestFormat 11 12def getBuildDir(cmd): 13 found = False 14 for arg in cmd: 15 if found: 16 return arg 17 if arg == '--build-dir': 18 found = True 19 return None 20 21def mkdir_p(path): 22 import errno 23 try: 24 os.makedirs(path) 25 except OSError as e: 26 if e.errno != errno.EEXIST: 27 raise 28 if not os.path.isdir(path): 29 raise OSError(errno.ENOTDIR, "%s is not a directory"%path) 30 31class LLDBTest(TestFormat): 32 def __init__(self, dotest_cmd): 33 self.dotest_cmd = dotest_cmd 34 35 def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, 36 localConfig): 37 source_path = testSuite.getSourcePath(path_in_suite) 38 for filename in os.listdir(source_path): 39 # Ignore dot files and excluded tests. 40 if (filename.startswith('.') or filename in localConfig.excludes): 41 continue 42 43 # Ignore files that don't start with 'Test'. 44 if not filename.startswith('Test'): 45 continue 46 47 filepath = os.path.join(source_path, filename) 48 if not os.path.isdir(filepath): 49 base, ext = os.path.splitext(filename) 50 if ext in localConfig.suffixes: 51 yield lit.Test.Test(testSuite, path_in_suite + 52 (filename, ), localConfig) 53 54 def execute(self, test, litConfig): 55 if litConfig.noExecute: 56 return lit.Test.PASS, '' 57 58 if not test.config.lldb_enable_python: 59 return (lit.Test.UNSUPPORTED, 'Python module disabled') 60 61 if test.config.unsupported: 62 return (lit.Test.UNSUPPORTED, 'Test is unsupported') 63 64 testPath, testFile = os.path.split(test.getSourcePath()) 65 66 # The Python used to run lit can be different from the Python LLDB was 67 # build with. 68 executable = test.config.python_executable 69 70 # On Windows, the system does not always correctly interpret 71 # shebang lines. To make sure we can execute the tests, add 72 # python exe as the first parameter of the command. 73 cmd = [executable] + self.dotest_cmd + [testPath, '-p', testFile] 74 75 builddir = getBuildDir(cmd) 76 mkdir_p(builddir) 77 78 # The macOS system integrity protection (SIP) doesn't allow injecting 79 # libraries into system binaries, but this can be worked around by 80 # copying the binary into a different location. 81 if 'DYLD_INSERT_LIBRARIES' in test.config.environment and \ 82 (executable.startswith('/System/') or \ 83 executable.startswith('/usr/bin/')): 84 copied_python = os.path.join(builddir, 'copied-system-python') 85 if not os.path.isfile(copied_python): 86 import shutil, subprocess 87 python = subprocess.check_output([ 88 executable, 89 '-c', 90 'import sys; print(sys.executable)' 91 ]).decode('utf-8').strip() 92 shutil.copy(python, copied_python) 93 cmd[0] = copied_python 94 95 if 'lldb-repro-capture' in test.config.available_features or \ 96 'lldb-repro-replay' in test.config.available_features: 97 reproducer_root = os.path.join(builddir, 'reproducers') 98 mkdir_p(reproducer_root) 99 reproducer_path = os.path.join(reproducer_root, testFile) 100 if 'lldb-repro-capture' in test.config.available_features: 101 cmd.extend(['--capture-path', reproducer_path]) 102 else: 103 cmd.extend(['--replay-path', reproducer_path]) 104 105 timeoutInfo = None 106 try: 107 out, err, exitCode = lit.util.executeCommand( 108 cmd, 109 env=test.config.environment, 110 timeout=litConfig.maxIndividualTestTime) 111 except lit.util.ExecuteCommandTimeoutException as e: 112 out = e.out 113 err = e.err 114 exitCode = e.exitCode 115 timeoutInfo = 'Reached timeout of {} seconds'.format( 116 litConfig.maxIndividualTestTime) 117 118 if sys.version_info.major == 2: 119 # In Python 2, string objects can contain Unicode characters. 120 out = out.decode('utf-8') 121 err = err.decode('utf-8') 122 123 output = """Script:\n--\n%s\n--\nExit Code: %d\n""" % ( 124 ' '.join(cmd), exitCode) 125 if timeoutInfo is not None: 126 output += """Timeout: %s\n""" % (timeoutInfo,) 127 output += "\n" 128 129 if out: 130 output += """Command Output (stdout):\n--\n%s\n--\n""" % (out,) 131 if err: 132 output += """Command Output (stderr):\n--\n%s\n--\n""" % (err,) 133 134 if timeoutInfo: 135 return lit.Test.TIMEOUT, output 136 137 if exitCode: 138 if 'XPASS:' in out or 'XPASS:' in err: 139 return lit.Test.XPASS, output 140 141 # Otherwise this is just a failure. 142 return lit.Test.FAIL, output 143 144 has_unsupported_tests = 'UNSUPPORTED:' in out or 'UNSUPPORTED:' in err 145 has_passing_tests = 'PASS:' in out or 'PASS:' in err 146 if has_unsupported_tests and not has_passing_tests: 147 return lit.Test.UNSUPPORTED, output 148 149 passing_test_line = 'RESULT: PASSED' 150 if passing_test_line not in out and passing_test_line not in err: 151 return lit.Test.UNRESOLVED, output 152 153 return lit.Test.PASS, output 154