Commit fb3e5af0 authored by Wez's avatar Wez Committed by Commit Bot

[fuchsia] Allow use of Fuchsia's 'run_test_component' to run tests.

Enable test packages to be made wholly or partially hermetic through use
of "fuchsia.test" facets in their package manifests.

- Remove the unused //build/fuchsia/exe_runner.py script.
- Rename run_package.py to run_test_package.py, and similarly for the
  methods and types it publishes.
- Update the RunTestPackage() API to support launching the component
  using the 'run_test_component' command, rather than 'run', if
  requested.

Bug: 1038786, 1132032
Change-Id: I42aaf996324542a2d6c6d6d93ea8bd1d0a878730
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1997698
Commit-Queue: Wez <wez@chromium.org>
Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Reviewed-by: default avatarKevin Marshall <kmarshall@chromium.org>
Auto-Submit: Wez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815696}
parent 6aa3f198
......@@ -56,7 +56,7 @@ class SSHPortForwarder(chrome_test_server_spawner.PortForwarder):
raise Exception('Unmap called for unknown port: %d' % device_port)
def SetupTestServer(target, test_concurrency, for_package):
def SetupTestServer(target, test_concurrency, for_package, for_realms=[]):
"""Provisions a forwarding test server and configures |target| to use it.
Returns a Popen object for the test server process."""
......@@ -82,7 +82,9 @@ def SetupTestServer(target, test_concurrency, for_package):
}))
config_file.flush()
target.PutFile(config_file.name, '/tmp/net-test-server-config',
for_package=for_package)
target.PutFile(config_file.name,
'/tmp/net-test-server-config',
for_package=for_package,
for_realms=for_realms)
return spawning_server
......@@ -148,23 +148,27 @@ def _GetComponentUri(package_name):
package_name)
class RunPackageArgs:
"""RunPackage() configuration arguments structure.
class RunTestPackageArgs:
"""RunTestPackage() configuration arguments structure.
symbolizer_config: A newline delimited list of source files contained
in the package. Omitting this parameter will disable symbolization.
system_logging: If set, connects a system log reader to the target.
test_realm_label: Specifies the realm name that run-test-component should use.
This must be specified if a filter file is to be set, or a results summary
file fetched after the test suite has run.
use_run_test_component: If True then the test package will be run hermetically
via 'run-test-component', rather than using 'run'.
"""
def __init__(self):
self.symbolizer_config = None
self.system_logging = False
self.test_realm_label = None
self.use_run_test_component = False
@staticmethod
def FromCommonArgs(args):
run_package_args = RunPackageArgs()
run_package_args.system_logging = args.include_system_logs
return run_package_args
run_test_package_args = RunTestPackageArgs()
run_test_package_args.system_logging = args.include_system_logs
return run_test_package_args
def _DrainStreamToStdout(stream, quit_event):
......@@ -179,8 +183,8 @@ def _DrainStreamToStdout(stream, quit_event):
print(line.rstrip())
def RunPackage(output_dir, target, package_paths, package_name, package_args,
args):
def RunTestPackage(output_dir, target, package_paths, package_name,
package_args, args):
"""Installs the Fuchsia package at |package_path| on the target,
executes it with |package_args|, and symbolizes its output.
......@@ -189,7 +193,7 @@ def RunPackage(output_dir, target, package_paths, package_name, package_args,
package_paths: The paths to the .far packages to be installed.
package_name: The name of the primary package to run.
package_args: The arguments which will be passed to the Fuchsia process.
args: Structure of arguments to configure how the package will be run.
args: RunTestPackageArgs instance configuring how the package will be run.
Returns the exit code of the remote package process."""
......@@ -213,7 +217,14 @@ def RunPackage(output_dir, target, package_paths, package_name, package_args,
log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS)
logging.info('Running application.')
command = ['run', _GetComponentUri(package_name)] + package_args
if args.use_run_test_component:
command = ['run-test-component']
if args.test_realm_label:
command += ['--realm-label=%s' % args.test_realm_label]
else:
command = ['run']
command += [_GetComponentUri(package_name)] + package_args
process = target.RunCommandPiped(command,
stdin=open(os.devnull, 'r'),
stdout=subprocess.PIPE,
......
......@@ -36,12 +36,13 @@ def _GetPackageInfo(package_path):
class _MapIsolatedPathsForPackage:
"""Callable object which remaps /data and /tmp paths to their package-specific
locations."""
"""Callable object which remaps /data and /tmp paths to their component-
specific locations, based on the package name and test realm path."""
def __init__(self, package_name, package_version):
package_sub_path = 'r/sys/fuchsia.com:{0}:{1}#meta:{0}.cmx/'.format(
package_name, package_version)
def __init__(self, package_name, package_version, realms):
realms_path_fragment = '/r/'.join(['r/sys'] + realms)
package_sub_path = '{2}/fuchsia.com:{0}:{1}#meta:{0}.cmx/'.format(
package_name, package_version, realms_path_fragment)
self.isolated_format = '{0}' + package_sub_path + '{1}'
def __call__(self, path):
......@@ -142,14 +143,21 @@ class Target(object):
return self.GetCommandRunner().RunCommand(command, silent,
timeout_secs=timeout_secs)
def EnsureIsolatedPathsExist(self, for_package):
def EnsureIsolatedPathsExist(self, for_package, for_realms):
"""Ensures that the package's isolated /data and /tmp exist."""
for isolated_directory in ['/data', '/tmp']:
self.RunCommand(
['mkdir','-p',
_MapIsolatedPathsForPackage(for_package, 0)(isolated_directory)])
def PutFile(self, source, dest, recursive=False, for_package=None):
self.RunCommand([
'mkdir', '-p',
_MapIsolatedPathsForPackage(for_package, 0,
for_realms)(isolated_directory)
])
def PutFile(self,
source,
dest,
recursive=False,
for_package=None,
for_realms=[]):
"""Copies a file from the local filesystem to the target filesystem.
source: The path of the file being copied.
......@@ -158,12 +166,19 @@ class Target(object):
for_package: If specified, isolated paths in the |dest| are mapped to their
obsolute paths for the package, on the target. This currently
affects the /data and /tmp directories.
for_realms: If specified, identifies the sub-realm of 'sys' under which
isolated paths (see |for_package|) are stored.
"""
assert type(source) is str
self.PutFiles([source], dest, recursive, for_package)
def PutFiles(self, sources, dest, recursive=False, for_package=None):
self.PutFiles([source], dest, recursive, for_package, for_realms)
def PutFiles(self,
sources,
dest,
recursive=False,
for_package=None,
for_realms=[]):
"""Copies files from the local filesystem to the target filesystem.
sources: List of local file paths to copy from, or a single path.
......@@ -171,39 +186,46 @@ class Target(object):
recursive: If true, performs a recursive copy.
for_package: If specified, /data in the |dest| is mapped to the package's
isolated /data location.
for_realms: If specified, identifies the sub-realm of 'sys' under which
isolated paths (see |for_package|) are stored.
"""
assert type(sources) is tuple or type(sources) is list
if for_package:
self.EnsureIsolatedPathsExist(for_package)
dest = _MapIsolatedPathsForPackage(for_package, 0)(dest)
self.EnsureIsolatedPathsExist(for_package, for_realms)
dest = _MapIsolatedPathsForPackage(for_package, 0, for_realms)(dest)
logging.debug('copy local:%s => remote:%s' % (sources, dest))
self.GetCommandRunner().RunScp(sources, dest, remote_cmd.COPY_TO_TARGET,
recursive)
def GetFile(self, source, dest, for_package=None):
def GetFile(self, source, dest, for_package=None, for_realms=[]):
"""Copies a file from the target filesystem to the local filesystem.
source: The path of the file being copied.
dest: The path on the local filesystem which will be copied to.
for_package: If specified, /data in paths in |sources| is mapped to the
package's isolated /data location.
for_realms: If specified, identifies the sub-realm of 'sys' under which
isolated paths (see |for_package|) are stored.
"""
assert type(source) is str
self.GetFiles([source], dest, for_package)
self.GetFiles([source], dest, for_package, for_realms)
def GetFiles(self, sources, dest, for_package=None):
def GetFiles(self, sources, dest, for_package=None, for_realms=[]):
"""Copies files from the target filesystem to the local filesystem.
sources: List of remote file paths to copy.
dest: The path on the local filesystem which will be copied to.
for_package: If specified, /data in paths in |sources| is mapped to the
package's isolated /data location.
for_realms: If specified, identifies the sub-realm of 'sys' under which
isolated paths (see |for_package|) are stored.
"""
assert type(sources) is tuple or type(sources) is list
self._AssertIsStarted()
if for_package:
sources = map(_MapIsolatedPathsForPackage(for_package, 0), sources)
sources = map(_MapIsolatedPathsForPackage(for_package, 0, for_realms),
sources)
logging.debug('copy remote:%s => local:%s' % (sources, dest))
return self.GetCommandRunner().RunScp(sources, dest,
remote_cmd.COPY_FROM_TARGET)
......
......@@ -13,7 +13,7 @@ import sys
from common_args import AddCommonArgs, ConfigureLogging, GetDeploymentTargetForArgs
from net_test_server import SetupTestServer
from run_package import RunPackage, RunPackageArgs, SystemLogReader
from run_test_package import RunTestPackage, RunTestPackageArgs, SystemLogReader
from runner_exceptions import HandleExceptionAndReturnExitCode
from runner_logs import RunnerLogManager
from symbolizer import BuildIdsPaths
......@@ -24,6 +24,9 @@ TEST_RESULT_PATH = '/data/test_summary.json'
TEST_PERF_RESULT_PATH = '/data/test_perf_summary.json'
TEST_FILTER_PATH = '/data/test_filter.txt'
TEST_REALM_NAME = 'chromium_tests'
def main():
parser = argparse.ArgumentParser()
AddCommonArgs(parser)
......@@ -84,6 +87,11 @@ def main():
help='If present, store test results on this path.')
parser.add_argument('--isolated-script-test-perf-output',
help='If present, store chartjson results on this path.')
parser.add_argument('--use-run-test-component',
default=False,
action='store_true',
help='Run the test package hermetically using '
'run-test-component, rather than run.')
args = parser.parse_args()
# Flag out_dir is required for tests launched with this script.
......@@ -146,6 +154,10 @@ def main():
if args.child_args:
child_args.extend(args.child_args)
test_realms = []
if args.use_run_test_component:
test_realms = [TEST_REALM_NAME]
try:
with GetDeploymentTargetForArgs() as target, \
SystemLogReader() as system_logger, \
......@@ -156,36 +168,46 @@ def main():
system_logger.Start(target, args.package, args.system_log_file)
if args.test_launcher_filter_file:
target.PutFile(args.test_launcher_filter_file, TEST_FILTER_PATH,
for_package=args.package_name)
target.PutFile(args.test_launcher_filter_file,
TEST_FILTER_PATH,
for_package=args.package_name,
for_realms=test_realms)
child_args.append('--test-launcher-filter-file=' + TEST_FILTER_PATH)
test_server = None
if args.enable_test_server:
assert test_concurrency
test_server = SetupTestServer(target, test_concurrency,
args.package_name)
args.package_name, test_realms)
run_package_args = RunPackageArgs.FromCommonArgs(args)
returncode = RunPackage(args.out_dir, target, args.package,
args.package_name, child_args, run_package_args)
run_package_args = RunTestPackageArgs.FromCommonArgs(args)
if args.use_run_test_component:
run_package_args.test_realm_label = TEST_REALM_NAME
run_package_args.use_run_test_component = True
returncode = RunTestPackage(args.out_dir, target, args.package,
args.package_name, child_args,
run_package_args)
if test_server:
test_server.Stop()
if args.test_launcher_summary_output:
target.GetFile(TEST_RESULT_PATH, args.test_launcher_summary_output,
for_package=args.package_name)
target.GetFile(TEST_RESULT_PATH,
args.test_launcher_summary_output,
for_package=args.package_name,
for_realms=test_realms)
if args.isolated_script_test_output:
target.GetFile(TEST_RESULT_PATH,
args.isolated_script_test_output,
for_package=args.package_name)
for_package=args.package_name,
for_realms=test_realms)
if args.isolated_script_test_perf_output:
target.GetFile(TEST_PERF_RESULT_PATH,
args.isolated_script_test_perf_output,
for_package=args.package_name)
for_package=args.package_name,
for_realms=test_realms)
return returncode
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment