2018-04-19 01:08:49 +08:00
|
|
|
from __future__ import absolute_import
|
|
|
|
import os
|
2020-04-14 23:41:50 +08:00
|
|
|
import tempfile
|
2018-04-19 01:08:49 +08:00
|
|
|
import subprocess
|
|
|
|
import sys
|
2020-05-08 07:07:32 +08:00
|
|
|
import platform
|
2018-04-19 01:08:49 +08:00
|
|
|
|
|
|
|
import lit.Test
|
|
|
|
import lit.TestRunner
|
|
|
|
import lit.util
|
|
|
|
from lit.formats.base import TestFormat
|
|
|
|
|
2018-08-24 01:19:08 +08:00
|
|
|
def getBuildDir(cmd):
|
|
|
|
found = False
|
|
|
|
for arg in cmd:
|
|
|
|
if found:
|
|
|
|
return arg
|
|
|
|
if arg == '--build-dir':
|
|
|
|
found = True
|
|
|
|
return None
|
2018-04-19 01:08:49 +08:00
|
|
|
|
2018-08-28 07:06:37 +08:00
|
|
|
def mkdir_p(path):
|
|
|
|
import errno
|
|
|
|
try:
|
|
|
|
os.makedirs(path)
|
|
|
|
except OSError as e:
|
|
|
|
if e.errno != errno.EEXIST:
|
|
|
|
raise
|
|
|
|
if not os.path.isdir(path):
|
|
|
|
raise OSError(errno.ENOTDIR, "%s is not a directory"%path)
|
|
|
|
|
2018-04-19 01:08:49 +08:00
|
|
|
class LLDBTest(TestFormat):
|
|
|
|
def __init__(self, dotest_cmd):
|
|
|
|
self.dotest_cmd = dotest_cmd
|
|
|
|
|
|
|
|
def getTestsInDirectory(self, testSuite, path_in_suite, litConfig,
|
|
|
|
localConfig):
|
|
|
|
source_path = testSuite.getSourcePath(path_in_suite)
|
|
|
|
for filename in os.listdir(source_path):
|
|
|
|
# Ignore dot files and excluded tests.
|
|
|
|
if (filename.startswith('.') or filename in localConfig.excludes):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Ignore files that don't start with 'Test'.
|
|
|
|
if not filename.startswith('Test'):
|
|
|
|
continue
|
|
|
|
|
|
|
|
filepath = os.path.join(source_path, filename)
|
|
|
|
if not os.path.isdir(filepath):
|
|
|
|
base, ext = os.path.splitext(filename)
|
|
|
|
if ext in localConfig.suffixes:
|
|
|
|
yield lit.Test.Test(testSuite, path_in_suite +
|
|
|
|
(filename, ), localConfig)
|
|
|
|
|
|
|
|
def execute(self, test, litConfig):
|
|
|
|
if litConfig.noExecute:
|
|
|
|
return lit.Test.PASS, ''
|
|
|
|
|
2019-12-14 02:37:33 +08:00
|
|
|
if not test.config.lldb_enable_python:
|
2018-06-06 17:44:14 +08:00
|
|
|
return (lit.Test.UNSUPPORTED, 'Python module disabled')
|
|
|
|
|
2018-04-19 01:08:49 +08:00
|
|
|
if test.config.unsupported:
|
|
|
|
return (lit.Test.UNSUPPORTED, 'Test is unsupported')
|
|
|
|
|
|
|
|
testPath, testFile = os.path.split(test.getSourcePath())
|
2020-05-07 05:33:34 +08:00
|
|
|
|
|
|
|
# The Python used to run lit can be different from the Python LLDB was
|
|
|
|
# build with.
|
|
|
|
executable = test.config.python_executable
|
|
|
|
|
2018-08-21 06:00:32 +08:00
|
|
|
# On Windows, the system does not always correctly interpret
|
|
|
|
# shebang lines. To make sure we can execute the tests, add
|
|
|
|
# python exe as the first parameter of the command.
|
2020-05-07 05:33:34 +08:00
|
|
|
cmd = [executable] + self.dotest_cmd + [testPath, '-p', testFile]
|
2018-04-19 01:08:49 +08:00
|
|
|
|
2020-04-14 23:41:50 +08:00
|
|
|
builddir = getBuildDir(cmd)
|
|
|
|
mkdir_p(builddir)
|
|
|
|
|
2020-05-08 07:07:32 +08:00
|
|
|
# On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim
|
|
|
|
# python binary as the ASan interceptors get loaded too late. Also,
|
|
|
|
# when SIP is enabled, we can't inject libraries into system binaries
|
|
|
|
# at all, so we need a copy of the "real" python to work with.
|
|
|
|
#
|
|
|
|
# Find the "real" python binary, copy it, and invoke it.
|
2018-08-24 01:51:14 +08:00
|
|
|
if 'DYLD_INSERT_LIBRARIES' in test.config.environment and \
|
2020-05-08 07:07:32 +08:00
|
|
|
platform.system() == 'Darwin':
|
2018-08-24 01:19:08 +08:00
|
|
|
copied_python = os.path.join(builddir, 'copied-system-python')
|
2018-08-28 07:06:38 +08:00
|
|
|
if not os.path.isfile(copied_python):
|
|
|
|
import shutil, subprocess
|
|
|
|
python = subprocess.check_output([
|
2020-05-07 05:33:34 +08:00
|
|
|
executable,
|
2020-05-08 07:07:32 +08:00
|
|
|
os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
|
|
|
'get_darwin_real_python.py')
|
2019-11-09 01:19:54 +08:00
|
|
|
]).decode('utf-8').strip()
|
2018-08-28 07:06:38 +08:00
|
|
|
shutil.copy(python, copied_python)
|
2018-08-24 01:19:08 +08:00
|
|
|
cmd[0] = copied_python
|
|
|
|
|
2020-04-14 23:41:50 +08:00
|
|
|
if 'lldb-repro-capture' in test.config.available_features or \
|
|
|
|
'lldb-repro-replay' in test.config.available_features:
|
|
|
|
reproducer_root = os.path.join(builddir, 'reproducers')
|
|
|
|
mkdir_p(reproducer_root)
|
|
|
|
reproducer_path = os.path.join(reproducer_root, testFile)
|
|
|
|
if 'lldb-repro-capture' in test.config.available_features:
|
|
|
|
cmd.extend(['--capture-path', reproducer_path])
|
|
|
|
else:
|
|
|
|
cmd.extend(['--replay-path', reproducer_path])
|
|
|
|
|
2020-01-25 08:11:18 +08:00
|
|
|
timeoutInfo = None
|
2018-04-19 01:08:49 +08:00
|
|
|
try:
|
|
|
|
out, err, exitCode = lit.util.executeCommand(
|
|
|
|
cmd,
|
|
|
|
env=test.config.environment,
|
|
|
|
timeout=litConfig.maxIndividualTestTime)
|
2020-01-31 13:23:58 +08:00
|
|
|
except lit.util.ExecuteCommandTimeoutException as e:
|
|
|
|
out = e.out
|
|
|
|
err = e.err
|
|
|
|
exitCode = e.exitCode
|
2020-01-25 08:11:18 +08:00
|
|
|
timeoutInfo = 'Reached timeout of {} seconds'.format(
|
|
|
|
litConfig.maxIndividualTestTime)
|
|
|
|
|
2020-04-21 23:25:44 +08:00
|
|
|
if sys.version_info.major == 2:
|
|
|
|
# In Python 2, string objects can contain Unicode characters.
|
|
|
|
out = out.decode('utf-8')
|
|
|
|
err = err.decode('utf-8')
|
|
|
|
|
2020-01-25 08:11:18 +08:00
|
|
|
output = """Script:\n--\n%s\n--\nExit Code: %d\n""" % (
|
|
|
|
' '.join(cmd), exitCode)
|
|
|
|
if timeoutInfo is not None:
|
|
|
|
output += """Timeout: %s\n""" % (timeoutInfo,)
|
|
|
|
output += "\n"
|
|
|
|
|
|
|
|
if out:
|
|
|
|
output += """Command Output (stdout):\n--\n%s\n--\n""" % (out,)
|
|
|
|
if err:
|
|
|
|
output += """Command Output (stderr):\n--\n%s\n--\n""" % (err,)
|
|
|
|
|
|
|
|
if timeoutInfo:
|
|
|
|
return lit.Test.TIMEOUT, output
|
2018-04-19 01:08:49 +08:00
|
|
|
|
|
|
|
if exitCode:
|
2018-12-21 04:44:23 +08:00
|
|
|
if 'XPASS:' in out or 'XPASS:' in err:
|
2020-01-25 08:11:18 +08:00
|
|
|
return lit.Test.XPASS, output
|
2018-12-18 05:40:37 +08:00
|
|
|
|
2020-02-25 15:20:41 +08:00
|
|
|
# Otherwise this is just a failure.
|
|
|
|
return lit.Test.FAIL, output
|
|
|
|
|
2019-09-26 03:31:54 +08:00
|
|
|
has_unsupported_tests = 'UNSUPPORTED:' in out or 'UNSUPPORTED:' in err
|
|
|
|
has_passing_tests = 'PASS:' in out or 'PASS:' in err
|
|
|
|
if has_unsupported_tests and not has_passing_tests:
|
2020-01-25 08:11:18 +08:00
|
|
|
return lit.Test.UNSUPPORTED, output
|
2019-09-26 03:31:54 +08:00
|
|
|
|
2018-04-19 01:08:49 +08:00
|
|
|
passing_test_line = 'RESULT: PASSED'
|
|
|
|
if passing_test_line not in out and passing_test_line not in err:
|
2020-01-25 08:11:18 +08:00
|
|
|
return lit.Test.UNRESOLVED, output
|
2018-04-19 01:08:49 +08:00
|
|
|
|
2020-01-25 08:11:18 +08:00
|
|
|
return lit.Test.PASS, output
|