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): ...@@ -56,7 +56,7 @@ class SSHPortForwarder(chrome_test_server_spawner.PortForwarder):
raise Exception('Unmap called for unknown port: %d' % device_port) 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. """Provisions a forwarding test server and configures |target| to use it.
Returns a Popen object for the test server process.""" Returns a Popen object for the test server process."""
...@@ -82,7 +82,9 @@ def SetupTestServer(target, test_concurrency, for_package): ...@@ -82,7 +82,9 @@ def SetupTestServer(target, test_concurrency, for_package):
})) }))
config_file.flush() config_file.flush()
target.PutFile(config_file.name, '/tmp/net-test-server-config', target.PutFile(config_file.name,
for_package=for_package) '/tmp/net-test-server-config',
for_package=for_package,
for_realms=for_realms)
return spawning_server return spawning_server
...@@ -148,23 +148,27 @@ def _GetComponentUri(package_name): ...@@ -148,23 +148,27 @@ def _GetComponentUri(package_name):
package_name) package_name)
class RunPackageArgs: class RunTestPackageArgs:
"""RunPackage() configuration arguments structure. """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. 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): def __init__(self):
self.symbolizer_config = None
self.system_logging = False self.system_logging = False
self.test_realm_label = None
self.use_run_test_component = False
@staticmethod @staticmethod
def FromCommonArgs(args): def FromCommonArgs(args):
run_package_args = RunPackageArgs() run_test_package_args = RunTestPackageArgs()
run_package_args.system_logging = args.include_system_logs run_test_package_args.system_logging = args.include_system_logs
return run_package_args return run_test_package_args
def _DrainStreamToStdout(stream, quit_event): def _DrainStreamToStdout(stream, quit_event):
...@@ -179,8 +183,8 @@ def _DrainStreamToStdout(stream, quit_event): ...@@ -179,8 +183,8 @@ def _DrainStreamToStdout(stream, quit_event):
print(line.rstrip()) print(line.rstrip())
def RunPackage(output_dir, target, package_paths, package_name, package_args, def RunTestPackage(output_dir, target, package_paths, package_name,
args): package_args, args):
"""Installs the Fuchsia package at |package_path| on the target, """Installs the Fuchsia package at |package_path| on the target,
executes it with |package_args|, and symbolizes its output. executes it with |package_args|, and symbolizes its output.
...@@ -189,7 +193,7 @@ def RunPackage(output_dir, target, package_paths, package_name, package_args, ...@@ -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_paths: The paths to the .far packages to be installed.
package_name: The name of the primary package to run. package_name: The name of the primary package to run.
package_args: The arguments which will be passed to the Fuchsia process. 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.""" Returns the exit code of the remote package process."""
...@@ -213,7 +217,14 @@ def RunPackage(output_dir, target, package_paths, package_name, package_args, ...@@ -213,7 +217,14 @@ def RunPackage(output_dir, target, package_paths, package_name, package_args,
log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS) log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS)
logging.info('Running application.') 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, process = target.RunCommandPiped(command,
stdin=open(os.devnull, 'r'), stdin=open(os.devnull, 'r'),
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
......
...@@ -36,12 +36,13 @@ def _GetPackageInfo(package_path): ...@@ -36,12 +36,13 @@ def _GetPackageInfo(package_path):
class _MapIsolatedPathsForPackage: class _MapIsolatedPathsForPackage:
"""Callable object which remaps /data and /tmp paths to their package-specific """Callable object which remaps /data and /tmp paths to their component-
locations.""" specific locations, based on the package name and test realm path."""
def __init__(self, package_name, package_version): def __init__(self, package_name, package_version, realms):
package_sub_path = 'r/sys/fuchsia.com:{0}:{1}#meta:{0}.cmx/'.format( realms_path_fragment = '/r/'.join(['r/sys'] + realms)
package_name, package_version) 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}' self.isolated_format = '{0}' + package_sub_path + '{1}'
def __call__(self, path): def __call__(self, path):
...@@ -142,14 +143,21 @@ class Target(object): ...@@ -142,14 +143,21 @@ class Target(object):
return self.GetCommandRunner().RunCommand(command, silent, return self.GetCommandRunner().RunCommand(command, silent,
timeout_secs=timeout_secs) 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.""" """Ensures that the package's isolated /data and /tmp exist."""
for isolated_directory in ['/data', '/tmp']: for isolated_directory in ['/data', '/tmp']:
self.RunCommand( self.RunCommand([
['mkdir','-p', 'mkdir', '-p',
_MapIsolatedPathsForPackage(for_package, 0)(isolated_directory)]) _MapIsolatedPathsForPackage(for_package, 0,
for_realms)(isolated_directory)
def PutFile(self, source, dest, recursive=False, for_package=None): ])
def PutFile(self,
source,
dest,
recursive=False,
for_package=None,
for_realms=[]):
"""Copies a file from the local filesystem to the target filesystem. """Copies a file from the local filesystem to the target filesystem.
source: The path of the file being copied. source: The path of the file being copied.
...@@ -158,12 +166,19 @@ class Target(object): ...@@ -158,12 +166,19 @@ class Target(object):
for_package: If specified, isolated paths in the |dest| are mapped to their for_package: If specified, isolated paths in the |dest| are mapped to their
obsolute paths for the package, on the target. This currently obsolute paths for the package, on the target. This currently
affects the /data and /tmp directories. 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 assert type(source) is str
self.PutFiles([source], dest, recursive, for_package) self.PutFiles([source], dest, recursive, for_package, for_realms)
def PutFiles(self, sources, dest, recursive=False, for_package=None): def PutFiles(self,
sources,
dest,
recursive=False,
for_package=None,
for_realms=[]):
"""Copies files from the local filesystem to the target filesystem. """Copies files from the local filesystem to the target filesystem.
sources: List of local file paths to copy from, or a single path. sources: List of local file paths to copy from, or a single path.
...@@ -171,39 +186,46 @@ class Target(object): ...@@ -171,39 +186,46 @@ class Target(object):
recursive: If true, performs a recursive copy. recursive: If true, performs a recursive copy.
for_package: If specified, /data in the |dest| is mapped to the package's for_package: If specified, /data in the |dest| is mapped to the package's
isolated /data location. 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 assert type(sources) is tuple or type(sources) is list
if for_package: if for_package:
self.EnsureIsolatedPathsExist(for_package) self.EnsureIsolatedPathsExist(for_package, for_realms)
dest = _MapIsolatedPathsForPackage(for_package, 0)(dest) dest = _MapIsolatedPathsForPackage(for_package, 0, for_realms)(dest)
logging.debug('copy local:%s => remote:%s' % (sources, dest)) logging.debug('copy local:%s => remote:%s' % (sources, dest))
self.GetCommandRunner().RunScp(sources, dest, remote_cmd.COPY_TO_TARGET, self.GetCommandRunner().RunScp(sources, dest, remote_cmd.COPY_TO_TARGET,
recursive) 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. """Copies a file from the target filesystem to the local filesystem.
source: The path of the file being copied. source: The path of the file being copied.
dest: The path on the local filesystem which will be copied to. 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 for_package: If specified, /data in paths in |sources| is mapped to the
package's isolated /data location. 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 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. """Copies files from the target filesystem to the local filesystem.
sources: List of remote file paths to copy. sources: List of remote file paths to copy.
dest: The path on the local filesystem which will be copied to. 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 for_package: If specified, /data in paths in |sources| is mapped to the
package's isolated /data location. 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 assert type(sources) is tuple or type(sources) is list
self._AssertIsStarted() self._AssertIsStarted()
if for_package: 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)) logging.debug('copy remote:%s => local:%s' % (sources, dest))
return self.GetCommandRunner().RunScp(sources, dest, return self.GetCommandRunner().RunScp(sources, dest,
remote_cmd.COPY_FROM_TARGET) remote_cmd.COPY_FROM_TARGET)
......
...@@ -13,7 +13,7 @@ import sys ...@@ -13,7 +13,7 @@ import sys
from common_args import AddCommonArgs, ConfigureLogging, GetDeploymentTargetForArgs from common_args import AddCommonArgs, ConfigureLogging, GetDeploymentTargetForArgs
from net_test_server import SetupTestServer 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_exceptions import HandleExceptionAndReturnExitCode
from runner_logs import RunnerLogManager from runner_logs import RunnerLogManager
from symbolizer import BuildIdsPaths from symbolizer import BuildIdsPaths
...@@ -24,6 +24,9 @@ TEST_RESULT_PATH = '/data/test_summary.json' ...@@ -24,6 +24,9 @@ TEST_RESULT_PATH = '/data/test_summary.json'
TEST_PERF_RESULT_PATH = '/data/test_perf_summary.json' TEST_PERF_RESULT_PATH = '/data/test_perf_summary.json'
TEST_FILTER_PATH = '/data/test_filter.txt' TEST_FILTER_PATH = '/data/test_filter.txt'
TEST_REALM_NAME = 'chromium_tests'
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
AddCommonArgs(parser) AddCommonArgs(parser)
...@@ -84,6 +87,11 @@ def main(): ...@@ -84,6 +87,11 @@ def main():
help='If present, store test results on this path.') help='If present, store test results on this path.')
parser.add_argument('--isolated-script-test-perf-output', parser.add_argument('--isolated-script-test-perf-output',
help='If present, store chartjson results on this path.') 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() args = parser.parse_args()
# Flag out_dir is required for tests launched with this script. # Flag out_dir is required for tests launched with this script.
...@@ -146,6 +154,10 @@ def main(): ...@@ -146,6 +154,10 @@ def main():
if args.child_args: if args.child_args:
child_args.extend(args.child_args) child_args.extend(args.child_args)
test_realms = []
if args.use_run_test_component:
test_realms = [TEST_REALM_NAME]
try: try:
with GetDeploymentTargetForArgs() as target, \ with GetDeploymentTargetForArgs() as target, \
SystemLogReader() as system_logger, \ SystemLogReader() as system_logger, \
...@@ -156,36 +168,46 @@ def main(): ...@@ -156,36 +168,46 @@ def main():
system_logger.Start(target, args.package, args.system_log_file) system_logger.Start(target, args.package, args.system_log_file)
if args.test_launcher_filter_file: if args.test_launcher_filter_file:
target.PutFile(args.test_launcher_filter_file, TEST_FILTER_PATH, target.PutFile(args.test_launcher_filter_file,
for_package=args.package_name) TEST_FILTER_PATH,
for_package=args.package_name,
for_realms=test_realms)
child_args.append('--test-launcher-filter-file=' + TEST_FILTER_PATH) child_args.append('--test-launcher-filter-file=' + TEST_FILTER_PATH)
test_server = None test_server = None
if args.enable_test_server: if args.enable_test_server:
assert test_concurrency assert test_concurrency
test_server = SetupTestServer(target, test_concurrency, test_server = SetupTestServer(target, test_concurrency,
args.package_name) args.package_name, test_realms)
run_package_args = RunPackageArgs.FromCommonArgs(args) run_package_args = RunTestPackageArgs.FromCommonArgs(args)
returncode = RunPackage(args.out_dir, target, args.package, if args.use_run_test_component:
args.package_name, child_args, run_package_args) 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: if test_server:
test_server.Stop() test_server.Stop()
if args.test_launcher_summary_output: if args.test_launcher_summary_output:
target.GetFile(TEST_RESULT_PATH, args.test_launcher_summary_output, target.GetFile(TEST_RESULT_PATH,
for_package=args.package_name) args.test_launcher_summary_output,
for_package=args.package_name,
for_realms=test_realms)
if args.isolated_script_test_output: if args.isolated_script_test_output:
target.GetFile(TEST_RESULT_PATH, target.GetFile(TEST_RESULT_PATH,
args.isolated_script_test_output, 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: if args.isolated_script_test_perf_output:
target.GetFile(TEST_PERF_RESULT_PATH, target.GetFile(TEST_PERF_RESULT_PATH,
args.isolated_script_test_perf_output, args.isolated_script_test_perf_output,
for_package=args.package_name) for_package=args.package_name,
for_realms=test_realms)
return returncode 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