0

Add a Tast mode to cros VM test runner.

Tast is a new suite of tests. It's invoked via "local_test_runner" in
the VM. You pass it a set of test names and it'll exercise some test
cases. We shouldn't use much more than the browser flavored ones.

Bug: 876587
Change-Id: I1d6ae9b6b5a929daadb6c12751cb0cd632a24d95
Reviewed-on: https://chromium-review.googlesource.com/1237673
Commit-Queue: Ben Pastene <bpastene@chromium.org>
Reviewed-by: John Budorick <jbudorick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594075}
This commit is contained in:
Ben Pastene
2018-09-25 20:13:25 +00:00
committed by Commit Bot
parent e9937698d9
commit 70849d7634

@ -29,6 +29,8 @@ sys.path.insert(
0, os.path.join(CHROMIUM_SRC_PATH, 'tools', 'swarming_client', 'utils'))
import subprocess42 # pylint: disable=import-error
DEFAULT_CROS_CACHE = os.path.abspath(os.path.join(
CHROMIUM_SRC_PATH, 'build', 'cros_cache'))
CHROMITE_PATH = os.path.abspath(os.path.join(
CHROMIUM_SRC_PATH, 'third_party', 'chromite'))
CROS_RUN_VM_TEST_PATH = os.path.abspath(os.path.join(
@ -47,7 +49,6 @@ class RemoteTest(object):
def __init__(self, args, unknown_args):
self._additional_args = unknown_args
self._path_to_outdir = args.path_to_outdir
self._test_exe = args.test_exe
self._test_launcher_summary_output = args.test_launcher_summary_output
self._vm_logs_dir = args.vm_logs_dir
@ -67,6 +68,10 @@ class RemoteTest(object):
'--results-dest-dir', args.vm_logs_dir,
]
@property
def suite_name(self):
raise NotImplementedError('Child classes need to define suite name.')
@property
def vm_test_cmd(self):
return self._vm_test_cmd
@ -119,7 +124,45 @@ class RemoteTest(object):
return test_proc.returncode
def post_run(self, return_code):
raise NotImplementedError()
# Create a simple json results file for a test run. The results will contain
# only one test (suite_name), and will either be a PASS or FAIL depending on
# return_code.
if self._test_launcher_summary_output:
result = (base_test_result.ResultType.FAIL if return_code else
base_test_result.ResultType.PASS)
suite_result = base_test_result.BaseTestResult(self.suite_name, result)
run_results = base_test_result.TestRunResults()
run_results.AddResult(suite_result)
with open(self._test_launcher_summary_output, 'w') as f:
json.dump(json_results.GenerateResultsDict([run_results]), f)
class TastTest(RemoteTest):
def __init__(self, args, unknown_args):
super(TastTest, self).__init__(args, unknown_args)
self._suite_name = args.suite_name
self._tests = args.tests
@property
def suite_name(self):
return self._suite_name
def build_test_command(self):
if self._additional_args:
raise TestFormatError(
'Tast tests should not have additional args: %s' % (
self._additional_args))
self._vm_test_cmd += [
'--deploy',
'--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
'--cmd',
'--',
'local_test_runner',
]
self._vm_test_cmd.extend(self._tests)
class GTestTest(RemoteTest):
@ -133,6 +176,7 @@ class GTestTest(RemoteTest):
def __init__(self, args, unknown_args):
super(GTestTest, self).__init__(args, unknown_args)
self._test_exe = args.test_exe
self._runtime_deps_path = args.runtime_deps_path
self._vpython_dir = args.vpython_dir
@ -141,6 +185,10 @@ class GTestTest(RemoteTest):
self._on_vm_script = None
@property
def suite_name(self):
return self._test_exe
def build_test_command(self):
# To keep things easy for us, ensure both types of output locations are
# the same.
@ -284,6 +332,10 @@ class BrowserSanityTest(RemoteTest):
self._retries = 2
self._timeout = 300
@property
def suite_name(self):
return SANITY_TEST_TARGET
def build_test_command(self):
if '--gtest_filter=%s' % SANITY_TEST_TARGET in self._additional_args:
logging.info(
@ -317,20 +369,6 @@ class BrowserSanityTest(RemoteTest):
self._test_env['PATH'] = (
self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
def post_run(self, return_code):
# Create a simple json results file for the sanity test if needed. The
# results will contain only one test (SANITY_TEST_TARGET), and will
# either be a PASS or FAIL depending on the return code of cros_run_vm_test.
if self._test_launcher_summary_output:
result = (base_test_result.ResultType.FAIL if return_code else
base_test_result.ResultType.PASS)
sanity_test_result = base_test_result.BaseTestResult(
SANITY_TEST_TARGET, result)
run_results = base_test_result.TestRunResults()
run_results.AddResult(sanity_test_result)
with open(self._test_launcher_summary_output, 'w') as f:
json.dump(json_results.GenerateResultsDict([run_results]), f)
def vm_test(args, unknown_args):
# cros_run_vm_test has trouble with relative paths that go up directories,
@ -340,7 +378,9 @@ def vm_test(args, unknown_args):
# pylint: disable=redefined-variable-type
# TODO: Remove the above when depot_tool's pylint is updated to include the
# fix to https://github.com/PyCQA/pylint/issues/710.
if args.test_exe == SANITY_TEST_TARGET:
if args.test_type == 'tast':
test = TastTest(args, unknown_args)
elif args.test_exe == SANITY_TEST_TARGET:
test = BrowserSanityTest(args, unknown_args)
else:
test = GTestTest(args, unknown_args)
@ -402,6 +442,30 @@ def host_cmd(args, unknown_args):
cros_run_vm_test_cmd, stdout=sys.stdout, stderr=sys.stderr, env=test_env)
def add_common_args(parser):
parser.add_argument(
'--cros-cache', type=str, default=DEFAULT_CROS_CACHE,
help='Path to cros cache.')
parser.add_argument(
'--path-to-outdir', type=str, required=True,
help='Path to output directory, all of whose contents will be '
'deployed to the device.')
parser.add_argument(
'--runtime-deps-path', type=str,
help='Runtime data dependency file from GN.')
parser.add_argument(
'--vpython-dir', type=str,
help='Location on host of a directory containing a vpython binary to '
'deploy to the VM before the test starts. The location of this '
'dir will be added onto PATH in the VM. WARNING: The arch of the '
'VM might not match the arch of the host, so avoid using '
'"${platform}" when downloading vpython via CIPD.')
parser.add_argument(
'--vm-logs-dir', type=str,
help='Will copy everything under /var/log/ from the VM after the test '
'into the specified dir.')
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
@ -416,7 +480,8 @@ def main():
'"--". Hostname and port for the VM will be 127.0.0.1:9222.')
host_cmd_parser.set_defaults(func=host_cmd)
host_cmd_parser.add_argument(
'--cros-cache', type=str, required=True, help='Path to cros cache.')
'--cros-cache', type=str, default=DEFAULT_CROS_CACHE,
help='Path to cros cache.')
host_cmd_parser.add_argument(
'--path-to-outdir', type=os.path.realpath,
help='Path to output directory, all of whose contents will be deployed '
@ -426,14 +491,13 @@ def main():
help='Will deploy a locally built Chrome binary to the VM before running '
'the host-cmd.')
host_cmd_parser.add_argument('cmd', nargs=argparse.REMAINDER)
# VM-side test args.
vm_test_parser = subparsers.add_parser(
# GTest args.
# TODO(bpastene): Rename 'vm-test' arg to 'gtest'.
gtest_parser = subparsers.add_parser(
'vm-test',
help='Runs a vm-side gtest.')
vm_test_parser.set_defaults(func=vm_test)
vm_test_parser.add_argument(
'--cros-cache', type=str, required=True, help='Path to cros cache.')
vm_test_parser.add_argument(
gtest_parser.set_defaults(func=vm_test)
gtest_parser.add_argument(
'--test-exe', type=str, required=True,
help='Path to test executable to run inside VM. If the value is '
'%s, the sanity test that ships with the VM '
@ -444,39 +508,39 @@ def main():
# GTest args. Some are passed down to the test binary in the VM. Others are
# parsed here since they might need tweaking or special handling.
vm_test_parser.add_argument(
gtest_parser.add_argument(
'--test-launcher-summary-output', type=str,
help='When set, will pass the same option down to the test and retrieve '
'its result file at the specified location.')
# Shard args are parsed here since we might also specify them via env vars.
vm_test_parser.add_argument(
gtest_parser.add_argument(
'--test-launcher-shard-index',
type=int, default=os.environ.get('GTEST_SHARD_INDEX', 0),
help='Index of the external shard to run.')
vm_test_parser.add_argument(
gtest_parser.add_argument(
'--test-launcher-total-shards',
type=int, default=os.environ.get('GTEST_TOTAL_SHARDS', 1),
help='Total number of external shards.')
# Misc args.
vm_test_parser.add_argument(
'--path-to-outdir', type=str, required=True,
help='Path to output directory, all of whose contents will be deployed '
'to the device.')
vm_test_parser.add_argument(
'--runtime-deps-path', type=str,
help='Runtime data dependency file from GN.')
vm_test_parser.add_argument(
'--vpython-dir', type=str,
help='Location on host of a directory containing a vpython binary to '
'deploy to the VM before the test starts. The location of this dir '
'will be added onto PATH in the VM. WARNING: The arch of the VM '
'might not match the arch of the host, so avoid using "${platform}" '
'when downloading vpython via CIPD.')
vm_test_parser.add_argument(
'--vm-logs-dir', type=str,
help='Will copy everything under /var/log/ from the VM after the test '
'into the specified dir.')
# Tast test args.
tast_test_parser = subparsers.add_parser(
'tast',
help='Runs a vm-side set of Tast tests.')
tast_test_parser.set_defaults(func=vm_test)
tast_test_parser.add_argument(
'--suite-name', type=str, required=True,
help='Name to apply to the set of Tast tests to run. This has no effect '
'on what is executed, but is used mainly for test results reporting '
'and tracking (eg: flakiness dashboard).')
tast_test_parser.add_argument(
'--test-launcher-summary-output', type=str,
help='Generates a simple GTest-style JSON result file for the test run.')
tast_test_parser.add_argument(
'--test', '-t', action='append', dest='tests', required=True,
help='A Tast test to run in the VM (eg: "ui.ChromeLogin").')
add_common_args(gtest_parser)
add_common_args(tast_test_parser)
args, unknown_args = parser.parse_known_args()
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARN)