Update the test configs to match the new layout.

Everything can be broken out into modules now, so there's not need to
keep the whole world in one file. This also brings us to the point
where we no longer require changes to any files in test/ compared to
upstream, only new files.

Change-Id: I3da27e12e6e2890355013c51567415436c4b517b
This commit is contained in:
Dan Albert
2015-01-09 18:03:29 +00:00
parent 036dcf6304
commit 8234f20ae7
8 changed files with 270 additions and 246 deletions

View File

View File

@@ -0,0 +1,24 @@
import lit.util # pylint: disable=import-error
class AdbError(RuntimeError):
def __init__(self, cmd, out, err, exit_code):
super(AdbError, self).__init__(err)
self.cmd = cmd
self.out = out
self.err = err
self.exit_code = exit_code
def mkdir(path):
cmd = ['adb', 'shell', 'mkdir', path]
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code != 0:
raise AdbError(cmd, out, err, exit_code)
def push(src, dst):
cmd = ['adb', 'push', src, dst]
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code != 0:
raise AdbError(cmd, out, err, exit_code)

View File

@@ -0,0 +1,13 @@
import os
import subprocess
def mm(path, android_build_top):
env = os.environ
env['ONE_SHOT_MAKEFILE'] = os.path.join(path, 'Android.mk')
cmd = [
'make', '-C', android_build_top, '-f', 'build/core/main.mk',
'all_modules', '-B'
]
return not subprocess.Popen(cmd, stdout=None, stderr=None, env=env).wait()

View File

View File

@@ -0,0 +1,99 @@
import os
import re
import subprocess
import libcxx.test.config
import libcxx.android.build
import libcxx.android.test.format
class Configuration(libcxx.test.config.Configuration):
def __init__(self, lit_config, config):
super(Configuration, self).__init__(lit_config, config)
self.cxx_under_test = None
self.build_cmds_dir = None
self.cxx_template = None
self.link_template = None
def configure(self):
self.configure_src_root()
self.configure_obj_root()
self.configure_build_cmds()
self.configure_cxx()
self.configure_cxx_template()
self.configure_link_template()
self.configure_triple()
self.configure_features()
def configure_build_cmds(self):
os.chdir(self.config.android_root)
self.build_cmds_dir = os.path.join(self.src_root, 'buildcmds')
if not libcxx.android.build.mm(self.build_cmds_dir,
self.config.android_root):
raise RuntimeError('Could not generate build commands.')
def configure_cxx(self):
cxx_under_test_file = os.path.join(self.build_cmds_dir,
'cxx_under_test')
self.cxx_under_test = open(cxx_under_test_file).read().strip()
def configure_cxx_template(self):
cxx_template_file = os.path.join(self.build_cmds_dir, 'cxx.cmds')
self.cxx_template = open(cxx_template_file).read().strip()
def configure_link_template(self):
link_template_file = os.path.join(self.build_cmds_dir, 'link.cmds')
self.link_template = open(link_template_file).read().strip()
def configure_triple(self):
if 'clang' in self.cxx_under_test:
triple = self.configure_clang_triple()
else:
triple = self.configure_gcc_triple()
if not triple:
raise RuntimeError('Could not determine target triple.')
self.config.target_triple = triple
def configure_clang_triple(self):
match = re.search(r'-target\s+(\S+)', self.cxx_template)
if match:
return match.group(1)
return None
def configure_gcc_triple(self):
proc = subprocess.Popen([self.cxx_under_test, '-v'],
stderr=subprocess.PIPE)
_, stderr = proc.communicate()
for line in stderr.split('\n'):
print 'Checking {}'.format(line)
match = re.search(r'^Target: (.+)$', line)
if match:
return match.group(1)
return None
def configure_features(self):
self.config.available_features.add('long_tests')
def get_test_format(self):
mode = self.lit_config.params.get('android_mode', 'device')
if mode == 'device':
return libcxx.android.test.format.TestFormat(
self.cxx_under_test,
self.src_root,
self.obj_root,
self.cxx_template,
self.link_template,
getattr(self.config, 'device_dir', '/data/local/tmp/'),
getattr(self.config, 'timeout', '60'))
elif mode == 'host':
return libcxx.android.test.format.HostTestFormat(
self.cxx_under_test,
self.src_root,
self.obj_root,
self.cxx_template,
self.link_template,
getattr(self.config, 'timeout', '60'))
else:
raise RuntimeError('Invalid android_mode: {}'.format(mode))

View File

@@ -0,0 +1,133 @@
import os
import shlex
import time
import lit.util # pylint: disable=import-error
import libcxx.test.format
import libcxx.android.adb as adb
class HostTestFormat(libcxx.test.format.LibcxxTestFormat):
# pylint: disable=super-init-not-called
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, timeout):
self.cxx_under_test = cxx_under_test
self.libcxx_src_root = libcxx_src_root
self.libcxx_obj_root = libcxx_obj_root
self.cxx_template = cxx_template
self.link_template = link_template
self.timeout = timeout
self.use_verify_for_fail = False
def _compile(self, output_path, source_path, use_verify=False):
if use_verify:
raise NotImplementedError(
'AndroidConfiguration does not support use_verify mode.')
cxx_args = self.cxx_template.replace('%OUT%', output_path)
cxx_args = cxx_args.replace('%SOURCE%', source_path)
cmd = [self.cxx_under_test] + shlex.split(cxx_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _link(self, exec_path, object_path):
link_args = self.link_template.replace('%OUT%', exec_path)
link_args = link_args.replace('%SOURCE%', object_path)
cmd = [self.cxx_under_test] + shlex.split(link_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _run(self, exec_path, lit_config, in_dir=None):
cmd = [exec_path]
# We need to use LD_LIBRARY_PATH because the build system's rpath is
# relative, which won't work since we're running from /tmp. We can
# either scan `cxx_under_test`/`link_template` to determine whether
# we're 32-bit or 64-bit, scan testconfig.mk, or just add both
# directories and let the linker sort it out. I'm choosing the lazy
# option.
outdir = os.getenv('ANDROID_HOST_OUT')
libpath = os.pathsep.join([
os.path.join(outdir, 'lib'),
os.path.join(outdir, 'lib64'),
])
out, err, rc = lit.util.executeCommand(
cmd, cwd=in_dir, env={'LD_LIBRARY_PATH': libpath})
return self._make_report(cmd, out, err, rc)
class TestFormat(HostTestFormat):
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, device_dir, timeout):
HostTestFormat.__init__(
self,
cxx_under_test,
libcxx_src_root,
libcxx_obj_root,
cxx_template,
link_template,
timeout)
self.device_dir = device_dir
def _working_directory(self, file_name):
return os.path.join(self.device_dir, file_name)
def _wd_path(self, test_name, file_name):
return os.path.join(self._working_directory(test_name), file_name)
def _build(self, exec_path, source_path, compile_only=False,
use_verify=False):
# pylint: disable=protected-access
cmd, report, rc = libcxx.test.format.LibcxxTestFormat._build(
self, exec_path, source_path, compile_only, use_verify)
if rc != 0:
return cmd, report, rc
try:
exec_file = os.path.basename(exec_path)
adb.mkdir(self._working_directory(exec_file))
adb.push(exec_path, self._wd_path(exec_file, exec_file))
# Push any .dat files in the same directory as the source to the
# working directory.
src_dir = os.path.dirname(source_path)
data_files = [f for f in os.listdir(src_dir) if f.endswith('.dat')]
for data_file in data_files:
df_path = os.path.join(src_dir, data_file)
df_dev_path = self._wd_path(exec_file, data_file)
adb.push(df_path, df_dev_path)
return cmd, report, rc
except adb.AdbError as ex:
return self._make_report(ex.cmd, ex.out, ex.err, ex.exit_code)
def _clean(self, exec_path):
exec_file = os.path.basename(exec_path)
cmd = ['adb', 'shell', 'rm', '-rf', self._working_directory(exec_file)]
lit.util.executeCommand(cmd)
os.remove(exec_path)
def _run(self, exec_path, lit_config, in_dir=None):
exec_file = os.path.basename(exec_path)
shell_cmd = 'cd {} && {}; echo $?'.format(
self._working_directory(exec_file),
self._wd_path(exec_file, exec_file))
cmd = ['timeout', self.timeout, 'adb', 'shell', shell_cmd]
# Tests will commonly fail with ETXTBSY. Possibly related to this bug:
# https://code.google.com/p/android/issues/detail?id=65857. Work around
# it by just waiting a second and then retrying.
for _ in range(10):
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code == 0:
if 'Text file busy' in out:
time.sleep(1)
else:
out = out.strip().split('\r\n')
status_line = out[-1:][0]
out = '\n'.join(out[:-1])
exit_code = int(status_line)
break
else:
err += '\nTimed out after {} seconds'.format(self.timeout)
break
return self._make_report(cmd, out, err, exit_code)

View File

@@ -6,251 +6,6 @@ import site
site.addsitedir(os.path.dirname(__file__))
class AndroidHostLibcxxTestFormat(LibcxxTestFormat):
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, timeout):
self.cxx_under_test = cxx_under_test
self.libcxx_src_root = libcxx_src_root
self.libcxx_obj_root = libcxx_obj_root
self.cxx_template = cxx_template
self.link_template = link_template
self.timeout = timeout
self.use_verify_for_fail = False
def _compile(self, output_path, source_path, use_verify=False):
if use_verify:
raise NotImplementedError(
'AndroidConfiguration does not support use_verify mode.')
cxx_args = self.cxx_template.replace('%OUT%', output_path)
cxx_args = cxx_args.replace('%SOURCE%', source_path)
cmd = [self.cxx_under_test] + shlex.split(cxx_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _link(self, exec_path, object_path):
link_args = self.link_template.replace('%OUT%', exec_path)
link_args = link_args.replace('%SOURCE%', object_path)
cmd = [self.cxx_under_test] + shlex.split(link_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _run(self, exec_path, lit_config, in_dir=None):
cmd = [exec_path]
# We need to use LD_LIBRARY_PATH because the build system's rpath is
# relative, which won't work since we're running from /tmp. We can
# either scan `cxx_under_test`/`link_template` to determine whether
# we're 32-bit or 64-bit, scan testconfig.mk, or just add both
# directories and let the linker sort it out. I'm choosing the lazy
# option.
outdir = os.getenv('ANDROID_HOST_OUT')
libpath = os.pathsep.join([
os.path.join(outdir, 'lib'),
os.path.join(outdir, 'lib64'),
])
out, err, rc = lit.util.executeCommand(
cmd, cwd=in_dir, env={'LD_LIBRARY_PATH': libpath})
return self._make_report(cmd, out, err, rc)
class AdbError(RuntimeError):
def __init__(self, cmd, out, err, exit_code):
self.cmd = cmd
self.out = out
self.err = err
self.exit_code = exit_code
class AndroidLibcxxTestFormat(AndroidHostLibcxxTestFormat):
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, device_dir, timeout):
AndroidHostLibcxxTestFormat.__init__(
self,
cxx_under_test,
libcxx_src_root,
libcxx_obj_root,
cxx_template,
link_template,
timeout)
self.device_dir = device_dir
def _working_directory(self, file_name):
return os.path.join(self.device_dir, file_name)
def _wd_path(self, test_name, file_name):
return os.path.join(self._working_directory(test_name), file_name)
def _adb_mkdir(self, path):
cmd = ['adb', 'shell', 'mkdir', path]
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code != 0:
raise AdbError(cmd, out, err, exit_code)
def _adb_push(self, src, dst):
cmd = ['adb', 'push', src, dst]
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code != 0:
raise AdbError(cmd, out, err, exit_code)
def _build(self, exec_path, source_path, compile_only=False,
use_verify=False):
cmd, report, rc = LibcxxTestFormat._build(
self, exec_path, source_path, compile_only, use_verify)
if rc != 0:
return cmd, report, rc
try:
exec_file = os.path.basename(exec_path)
self._adb_mkdir(self._working_directory(exec_file))
self._adb_push(exec_path, self._wd_path(exec_file, exec_file))
# Push any .dat files in the same directory as the source to the
# working directory.
src_dir = os.path.dirname(source_path)
data_files = [f for f in os.listdir(src_dir) if f.endswith('.dat')]
for data_file in data_files:
df_path = os.path.join(src_dir, data_file)
df_dev_path = self._wd_path(exec_file, data_file)
self._adb_push(df_path, df_dev_path)
return cmd, report, rc
except AdbError as ex:
return self._make_report(ex.cmd, ex.out, ex.err, ex.exit_code)
def _clean(self, exec_path):
exec_file = os.path.basename(exec_path)
cmd = ['adb', 'shell', 'rm', '-rf', self._working_directory(exec_file)]
lit.util.executeCommand(cmd)
os.remove(exec_path)
def _run(self, exec_path, lit_config, in_dir=None):
exec_file = os.path.basename(exec_path)
shell_cmd = 'cd {} && {}; echo $?'.format(
self._working_directory(exec_file),
self._wd_path(exec_file, exec_file))
cmd = ['timeout', self.timeout, 'adb', 'shell', shell_cmd]
# Tests will commonly fail with ETXTBSY. Possibly related to this bug:
# https://code.google.com/p/android/issues/detail?id=65857. Work around
# it by just waiting a second and then retrying.
for _ in range(10):
out, err, exit_code = lit.util.executeCommand(cmd)
if exit_code == 0:
if 'Text file busy' in out:
time.sleep(1)
else:
out = out.strip().split('\r\n')
status_line = out[-1:][0]
out = '\n'.join(out[:-1])
exit_code = int(status_line)
break
else:
err += '\nTimed out after {} seconds'.format(self.timeout)
break
return self._make_report(cmd, out, err, exit_code)
def mm(path, android_build_top):
env = os.environ
env['ONE_SHOT_MAKEFILE'] = os.path.join(path, 'Android.mk')
cmd = [
'make', '-C', android_build_top, '-f', 'build/core/main.mk',
'all_modules', '-B'
]
return not subprocess.Popen(cmd, stdout=None, stderr=None, env=env).wait()
class AndroidConfiguration(Configuration):
def __init__(self, lit_config, config):
super(AndroidConfiguration, self).__init__(lit_config, config)
self.cxx_under_test = None
self.build_cmds_dir = None
self.cxx_template = None
self.link_template = None
def configure(self):
self.configure_src_root()
self.configure_obj_root()
self.configure_build_cmds()
self.configure_cxx()
self.configure_cxx_template()
self.configure_link_template()
self.configure_triple()
self.configure_features()
def configure_build_cmds(self):
os.chdir(self.config.android_root)
self.build_cmds_dir = os.path.join(self.src_root, 'buildcmds')
if not mm(self.build_cmds_dir, self.config.android_root):
raise RuntimeError('Could not generate build commands.')
def configure_cxx(self):
cxx_under_test_file = os.path.join(self.build_cmds_dir,
'cxx_under_test')
self.cxx_under_test = open(cxx_under_test_file).read().strip()
def configure_cxx_template(self):
cxx_template_file = os.path.join(self.build_cmds_dir, 'cxx.cmds')
self.cxx_template = open(cxx_template_file).read().strip()
def configure_link_template(self):
link_template_file = os.path.join(self.build_cmds_dir, 'link.cmds')
self.link_template = open(link_template_file).read().strip()
def configure_triple(self):
if 'clang' in self.cxx_under_test:
triple = self.configure_clang_triple()
else:
triple = self.configure_gcc_triple()
if not triple:
raise RuntimeError('Could not determine target triple.')
self.config.target_triple = triple
def configure_clang_triple(self):
match = re.search(r'-target\s+(\S+)', self.cxx_template)
if match:
return match.group(1)
return None
def configure_gcc_triple(self):
proc = subprocess.Popen([self.cxx_under_test, '-v'],
stderr=subprocess.PIPE)
_, stderr = proc.communicate()
for line in stderr.split('\n'):
print 'Checking {}'.format(line)
match = re.search(r'^Target: (.+)$', line)
if match:
return match.group(1)
return None
def configure_features(self):
self.config.available_features.add('long_tests')
def get_test_format(self):
mode = self.lit_config.params.get('android_mode', 'device')
if mode == 'device':
return AndroidLibcxxTestFormat(
self.cxx_under_test,
self.src_root,
self.obj_root,
self.cxx_template,
self.link_template,
getattr(self.config, 'device_dir', '/data/local/tmp/'),
getattr(self.config, 'timeout', '60'))
elif mode == 'host':
return AndroidHostLibcxxTestFormat(
self.cxx_under_test,
self.src_root,
self.obj_root,
self.cxx_template,
self.link_template,
getattr(self.config, 'timeout', '60'))
else:
raise RuntimeError('Invalid android_mode: {}'.format(mode))
# Tell pylint that we know config and lit_config exist somewhere.
if 'PYLINT_IMPORT' in os.environ:
config = object()

View File

@@ -1,6 +1,6 @@
import os
config.configuration_variant = 'Android'
config.configuration_variant = 'libcxx.android'
config.android_root = os.getenv('ANDROID_BUILD_TOP')
config.libcxx_src_root = os.path.join(config.android_root, 'external/libcxx')
config.libcxx_obj_root = os.getenv('ANDROID_PRODUCT_OUT')