summaryrefslogtreecommitdiff
path: root/chromium/build/chromeos
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-24 11:40:17 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-24 12:42:11 +0000
commit5d87695f37678f96492b258bbab36486c59866b4 (patch)
treebe9783bbaf04fb930c4d74ca9c00b5e7954c8bc6 /chromium/build/chromeos
parent6c11fb357ec39bf087b8b632e2b1e375aef1b38b (diff)
downloadqtwebengine-chromium-5d87695f37678f96492b258bbab36486c59866b4.tar.gz
BASELINE: Update Chromium to 75.0.3770.56
Change-Id: I86d2007fd27a45d5797eee06f4c9369b8b50ac4f Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/build/chromeos')
-rwxr-xr-xchromium/build/chromeos/create_test_runner_script.py15
-rwxr-xr-xchromium/build/chromeos/test_runner.py379
2 files changed, 284 insertions, 110 deletions
diff --git a/chromium/build/chromeos/create_test_runner_script.py b/chromium/build/chromeos/create_test_runner_script.py
index 0cbe38bab77..161b9a71e5c 100755
--- a/chromium/build/chromeos/create_test_runner_script.py
+++ b/chromium/build/chromeos/create_test_runner_script.py
@@ -63,13 +63,7 @@ def main(args):
run_test_path = RelativizePathToScript(
os.path.join(os.path.dirname(__file__), 'test_runner.py'))
- vm_test_args = [
- '--board', args.board,
- '-v',
- ]
- if args.use_vm:
- vm_test_args += ['--use-vm']
-
+ vm_test_args = []
if args.test_exe:
vm_test_args.extend([
'vm-test',
@@ -95,6 +89,13 @@ def main(args):
if args.deploy_chrome:
vm_test_args.append('--deploy-chrome')
+ vm_test_args += [
+ '--board', args.board,
+ '-v',
+ ]
+ if args.use_vm:
+ vm_test_args += ['--use-vm']
+
vm_test_path_args = [
('--cros-cache', RelativizePathToScript(args.cros_cache)),
]
diff --git a/chromium/build/chromeos/test_runner.py b/chromium/build/chromeos/test_runner.py
index f5224ff276d..77c99fb0a71 100755
--- a/chromium/build/chromeos/test_runner.py
+++ b/chromium/build/chromeos/test_runner.py
@@ -15,6 +15,9 @@ import socket
import sys
import tempfile
+# The following non-std imports are fetched via vpython. See the list at
+# //.vpython
+import dateutil.parser # pylint: disable=import-error
import psutil # pylint: disable=import-error
CHROMIUM_SRC_PATH = os.path.abspath(os.path.join(
@@ -52,15 +55,34 @@ class TestFormatError(Exception):
class RemoteTest(object):
+ # This is a basic shell script that can be appended to in order to invoke the
+ # test on the device.
+ BASIC_SHELL_SCRIPT = [
+ '#!/bin/sh',
+
+ # /home is mounted with "noexec" in the device, but some of our tools
+ # and tests use the home dir as a workspace (eg: vpython downloads
+ # python binaries to ~/.vpython-root). /tmp doesn't have this
+ # restriction, so change the location of the home dir for the
+ # duration of the test.
+ 'export HOME=/tmp',
+ ]
+
def __init__(self, args, unknown_args):
self._additional_args = unknown_args
self._path_to_outdir = args.path_to_outdir
self._test_launcher_summary_output = args.test_launcher_summary_output
self._logs_dir = args.logs_dir
+ self._use_vm = args.use_vm
self._retries = 0
self._timeout = None
+ # The location on disk of a shell script that can be optionally used to
+ # invoke the test on the device. If it's not set, we assume self._test_cmd
+ # contains the test invocation.
+ self._on_device_script = None
+
self._test_cmd = [
CROS_RUN_TEST_PATH,
'--board', args.board,
@@ -83,6 +105,22 @@ class RemoteTest(object):
'--results-dest-dir', args.logs_dir,
]
+ # This environment variable is set for tests that have been instrumented
+ # for code coverage. Its incoming value is expected to be a location
+ # inside a subdirectory of result_dir above. This is converted to an
+ # absolute path that the vm is able to write to, and passed in the
+ # --results-src flag to cros_run_vm_test for copying out of the vm before
+ # its termination.
+ self._llvm_profile_var = None
+ if os.environ.get('LLVM_PROFILE_FILE'):
+ _, llvm_profile_file = os.path.split(os.environ['LLVM_PROFILE_FILE'])
+ self._llvm_profile_var = '/tmp/profraw/%s' % llvm_profile_file
+
+ # This should make the vm test runner exfil the profiling data.
+ self._test_cmd += [
+ '--results-src', '/tmp/profraw'
+ ]
+
self._test_env = setup_env()
@property
@@ -93,6 +131,21 @@ class RemoteTest(object):
def test_cmd(self):
return self._test_cmd
+ def write_test_script_to_disk(self, script_contents):
+ # Since we're using an on_device_script to invoke the test, we'll need to
+ # set cwd.
+ self._test_cmd += [
+ '--remote-cmd',
+ '--cwd', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
+ ]
+ logging.info('Running the following command on the device:')
+ logging.info('\n' + '\n'.join(script_contents))
+ fd, tmp_path = tempfile.mkstemp(suffix='.sh', dir=self._path_to_outdir)
+ os.fchmod(fd, 0755)
+ with os.fdopen(fd, 'wb') as f:
+ f.write('\n'.join(script_contents) + '\n')
+ return tmp_path
+
def run_test(self):
# Traps SIGTERM and kills all child processes of cros_run_test when it's
# caught. This will allow us to capture logs from the device if a test hangs
@@ -137,10 +190,16 @@ class RemoteTest(object):
if test_proc.returncode == 0:
break
- self.post_run(test_proc.returncode)
+ ret = self.post_run(test_proc.returncode)
+ # Allow post_run to override test proc return code. (Useful when the host
+ # side Tast bin returns 0 even for failed tests.)
+ if ret is not None:
+ return ret
return test_proc.returncode
def post_run(self, return_code):
+ if self._on_device_script:
+ os.remove(self._on_device_script)
# 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.
@@ -162,7 +221,14 @@ class TastTest(RemoteTest):
self._suite_name = args.suite_name
self._tests = args.tests
self._conditional = args.conditional
- self._use_vm = args.use_vm
+ self._use_host_tast = args.use_host_tast_bin
+
+ if self._use_host_tast and not self._logs_dir:
+ # The host-side Tast bin returns 0 when tests fail, so we need to capture
+ # and parse its json results to reliably determine if tests fail.
+ raise TestFormatError(
+ 'When using the host-side Tast bin, "--logs-dir" must be passed in '
+ 'order to parse its results.')
@property
def suite_name(self):
@@ -194,28 +260,133 @@ class TastTest(RemoteTest):
self._test_cmd += [
'--deploy',
+ '--mount',
'--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
- '--cmd',
- '--',
- 'local_test_runner',
- '-waituntilready',
]
- if self._use_vm:
- # If we're running tests in VMs, tell the test runner to skip tests that
- # aren't compatible.
- self._test_cmd.append('-extrauseflags=tast_vm')
- if self._conditional:
- self._test_cmd.append(pipes.quote(self._conditional))
+
+ # Coverage tests require some special pre-test setup, so use an
+ # on_device_script in that case. For all other tests, use cros_run_test's
+ # built-in '--tast' option. This gives us much better results reporting.
+ # TODO(bpastene): s/True/self._llvm_profile_var/ once we parse Tast results.
+ if not self._use_host_tast:
+ # Build the shell script that will be used on the device to invoke the
+ # test.
+ device_test_script_contents = self.BASIC_SHELL_SCRIPT[:]
+ if self._llvm_profile_var:
+ device_test_script_contents += [
+ 'echo "LLVM_PROFILE_FILE=%s" >> /etc/chrome_dev.conf' % (
+ self._llvm_profile_var)
+ ]
+
+ local_test_runner_cmd = ['local_test_runner', '-waituntilready']
+ if self._use_vm:
+ # If we're running tests in VMs, tell the test runner to skip tests that
+ # aren't compatible.
+ local_test_runner_cmd.append('-extrauseflags=tast_vm')
+ if self._conditional:
+ local_test_runner_cmd.append(pipes.quote(self._conditional))
+ else:
+ local_test_runner_cmd.extend(self._tests)
+ device_test_script_contents.append(' '.join(local_test_runner_cmd))
+
+ self._on_device_script = self.write_test_script_to_disk(
+ device_test_script_contents)
+
+ self._test_cmd += [
+ '--files', os.path.relpath(self._on_device_script),
+ '--',
+ './' + os.path.relpath(self._on_device_script, self._path_to_outdir)
+ ]
else:
- self._test_cmd.extend(self._tests)
+ self._test_cmd += [
+ # Since we're not in a chroot, the tast bin won't automatically handle
+ # ssh auth. So point it to the ssh keys in chromite.
+ '--private-key',
+ os.path.join(CHROMITE_PATH, 'ssh_keys', 'testing_rsa'),
+ ]
+ # Capture tast's results in the logs dir as well.
+ if self._logs_dir:
+ self._test_cmd += [
+ '--results-dir', self._logs_dir,
+ ]
+ if self._conditional:
+ # Don't use pipes.quote() here. Something funky happens with the arg
+ # as it gets passed down from cros_run_test to tast. (Tast picks up the
+ # escaping single quotes and complains that the conditional "must be
+ # within parentheses".)
+ self._test_cmd.append('--tast=%s' % self._conditional)
+ else:
+ self._test_cmd.append('--tast')
+ self._test_cmd.extend(self._tests)
+
+ def post_run(self, return_code):
+ # If we don't need to parse the host-side Tast tool's results, fall back to
+ # the parent method's default behavior.
+ if not self._use_host_tast:
+ return super(TastTest, self).post_run(return_code)
+
+ # TODO(crbug.com/952085): Switch to streamed_results.jsonl after jsonlines
+ # becomes available as a wheel.
+ tast_results_path = os.path.join(self._logs_dir, 'results.json')
+ if not os.path.exists(tast_results_path):
+ logging.error(
+ 'Tast results not found at %s. Falling back to generic result '
+ 'reporting.', tast_results_path)
+ return super(TastTest, self).post_run(return_code)
+
+ # See the link below for the format of the results:
+ # https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/chromiumos/cmd/tast/run#TestResult
+ with open(tast_results_path) as f:
+ tast_results = json.load(f)
+
+ suite_results = base_test_result.TestRunResults()
+ for test in tast_results:
+ errors = test['errors']
+ start, end = test['start'], test['end']
+ # Use dateutil to parse the timestamps since datetime can't handle
+ # nanosecond precision.
+ duration = dateutil.parser.parse(end) - dateutil.parser.parse(start)
+ duration_ms = duration.total_seconds() * 1000
+ if bool(test['skipReason']):
+ result = base_test_result.ResultType.SKIP
+ elif errors:
+ result = base_test_result.ResultType.FAIL
+ else:
+ result = base_test_result.ResultType.PASS
+ error_log = ''
+ if errors:
+ # See the link below for the format of these errors:
+ # https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/chromiumos/tast/testing#Error
+ for err in errors:
+ error_log += str(err['stack']) + '\n'
+ base_result = base_test_result.BaseTestResult(
+ test['name'], result, duration=duration_ms, log=error_log)
+ suite_results.AddResult(base_result)
+
+ if self._test_launcher_summary_output:
+ with open(self._test_launcher_summary_output, 'w') as f:
+ json.dump(json_results.GenerateResultsDict([suite_results]), f)
+
+ if not suite_results.DidRunPass():
+ return 1
+ return 0
+
class GTestTest(RemoteTest):
+ # The following list corresponds to paths that should not be copied over to
+ # the device during tests. In other words, these files are only ever used on
+ # the host.
_FILE_BLACKLIST = [
+ re.compile(r'.*build/android.*'),
re.compile(r'.*build/chromeos.*'),
re.compile(r'.*build/cros_cache.*'),
+ # The following matches anything under //testing/ that isn't under
+ # //testing/buildbot/filters/.
+ re.compile(r'.*testing/(?!buildbot/filters).*'),
re.compile(r'.*third_party/chromite.*'),
+ re.compile(r'.*tools/swarming_client.*'),
]
def __init__(self, args, unknown_args):
@@ -230,9 +401,6 @@ class GTestTest(RemoteTest):
self._on_device_script = None
- # If set, pass this value to the LLVM_PROFILE_FILE env var in the vm.
- self._vm_profile_var = None
-
@property
def suite_name(self):
return self._test_exe
@@ -261,34 +429,11 @@ class GTestTest(RemoteTest):
'--results-dest-dir', result_dir,
]
- # This environment variable is set for tests that have been instrumented
- # for code coverage. Its incoming value is expected to be a location
- # inside a subdirectory of result_dir above. This is converted to an
- # absolute path that the vm is able to write to, and passed in the
- # --results-src flag to cros_run_vm_test for copying out of the vm before
- # its termination.
- if os.environ.get('LLVM_PROFILE_FILE'):
- _, vm_profile_file = os.path.split(os.environ['LLVM_PROFILE_FILE'])
- self._vm_profile_var = '/tmp/profraw/%s' % vm_profile_file
-
- # This should make the vm test runner exfil the profiling data.
- self._test_cmd += [
- '--results-src', '/tmp/profraw'
- ]
-
# Build the shell script that will be used on the device to invoke the test.
- device_test_script_contents = ['#!/bin/sh']
-
- # /home is mounted with "noexec" in the device, but some of our tools
- # and tests use the home dir as a workspace (eg: vpython downloads
- # python binaries to ~/.vpython-root). /tmp doesn't have this
- # restriction, so change the location of the home dir for the
- # duration of the test.
- device_test_script_contents.append('export HOME=/tmp')
-
- if self._vm_profile_var:
+ device_test_script_contents = self.BASIC_SHELL_SCRIPT[:]
+ if self._llvm_profile_var:
device_test_script_contents += [
- 'export LLVM_PROFILE_FILE=%s'% self._vm_profile_var,
+ 'export LLVM_PROFILE_FILE=%s'% self._llvm_profile_var,
]
if self._vpython_dir:
@@ -321,15 +466,31 @@ class GTestTest(RemoteTest):
device_result_file)
if self._additional_args:
test_invocation += ' %s' % ' '.join(self._additional_args)
+
+ if self._test_exe == 'interactive_ui_tests':
+ # interactive_ui_tests needs some special setup. See crbug.com/946685#c4
+ # TODO(bpastene): Put all this behind a flag if more suites need it.
+ device_test_script_contents += [
+ 'stop ui',
+ ]
+ # The UI service on the device owns the chronos user session, so shutting
+ # it down as chronos kills the entire execution of the test. So we'll have
+ # to run as root up until the test invocation.
+ test_invocation = 'su chronos -c -- "%s"' % test_invocation
+ # And we'll need to chown everything since cros_run_test's "--as-chronos"
+ # option normally does that for us.
+ device_test_script_contents.append('chown -R chronos: ../..')
+ else:
+ self._test_cmd += [
+ # Some tests fail as root, so run as the less privileged user
+ # 'chronos'.
+ '--as-chronos',
+ ]
+
device_test_script_contents.append(test_invocation)
- logging.info('Running the following command on the device:')
- logging.info('\n' + '\n'.join(device_test_script_contents))
- fd, tmp_path = tempfile.mkstemp(suffix='.sh', dir=self._path_to_outdir)
- os.fchmod(fd, 0755)
- with os.fdopen(fd, 'wb') as f:
- f.write('\n'.join(device_test_script_contents))
- self._on_device_script = tmp_path
+ self._on_device_script = self.write_test_script_to_disk(
+ device_test_script_contents)
runtime_files = [os.path.relpath(self._on_device_script)]
runtime_files += self._read_runtime_files()
@@ -345,16 +506,10 @@ class GTestTest(RemoteTest):
# of handling it here.
runtime_files.append('.vpython')
- # Since we're pushing files, we need to set the cwd.
- self._test_cmd.extend(
- ['--cwd', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH)])
for f in runtime_files:
self._test_cmd.extend(['--files', f])
self._test_cmd += [
- # Some tests fail as root, so run as the less privileged user 'chronos'.
- '--as-chronos',
- '--cmd',
'--',
'./' + os.path.relpath(self._on_device_script, self._path_to_outdir)
]
@@ -412,13 +567,33 @@ class BrowserSanityTest(RemoteTest):
'Sanity test should not have additional args: %s' % (
self._additional_args))
- # run_cros_test's default behavior when no cmd is specified is the sanity
- # test that's baked into the device image. This test smoke-checks the system
- # browser, so deploy our locally-built chrome to the device before testing.
+ # VMs don't have the disk space for an unstripped version of Chrome
+ # instrumented for code coverage, so only strip in that case.
+ if not self._use_vm or not os.environ.get('LLVM_PROFILE_FILE'):
+ self._test_cmd.append('--nostrip')
+
+ device_test_script_contents = self.BASIC_SHELL_SCRIPT[:]
+ if self._llvm_profile_var:
+ device_test_script_contents += [
+ 'echo "LLVM_PROFILE_FILE=%s" >> /etc/chrome_dev.conf' % (
+ self._llvm_profile_var)
+ ]
+
+ # vm_sanity.py is the sanity test, which is baked into the device image.
+ device_test_script_contents.append('/usr/local/autotest/bin/vm_sanity.py')
+
+ self._on_device_script = self.write_test_script_to_disk(
+ device_test_script_contents)
+
self._test_cmd += [
+ '--files', os.path.relpath(self._on_device_script),
+ # The sanity test smoke-checks the system browser, so deploy our
+ # locally-built chrome to the device before testing.
'--deploy',
- '--nostrip',
+ '--mount',
'--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
+ '--',
+ './' + os.path.relpath(self._on_device_script, self._path_to_outdir)
]
@@ -478,6 +653,7 @@ def host_cmd(args, unknown_args):
if args.deploy_chrome:
cros_run_test_cmd += [
'--deploy',
+ '--mount',
'--build-dir', os.path.abspath(args.path_to_outdir),
]
@@ -511,45 +687,46 @@ def setup_env():
return 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 device before the test starts. The location of this '
- 'dir will be added onto PATH in the device. WARNING: The arch of '
- 'the device might not match the arch of the host, so avoid using '
- '"${platform}" when downloading vpython via CIPD.')
- # TODO(bpastene): Switch all uses of "--vm-logs-dir" to "--logs-dir".
- parser.add_argument(
- '--vm-logs-dir', '--logs-dir', type=str, dest='logs_dir',
- help='Will copy everything under /var/log/ from the device after the '
- 'test into the specified dir.')
+def add_common_args(*parsers):
+ for parser in parsers:
+ parser.add_argument('--verbose', '-v', action='store_true')
+ parser.add_argument(
+ '--board', type=str, required=True, help='Type of CrOS device.')
+ 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 device before the test starts. The location of '
+ 'this dir will be added onto PATH in the device. WARNING: The '
+ 'arch of the device might not match the arch of the host, so '
+ 'avoid using "${platform}" when downloading vpython via CIPD.')
+ # TODO(bpastene): Switch all uses of "--vm-logs-dir" to "--logs-dir".
+ parser.add_argument(
+ '--vm-logs-dir', '--logs-dir', type=str, dest='logs_dir',
+ help='Will copy everything under /var/log/ from the device after the '
+ 'test into the specified dir.')
+
+ vm_or_device_group = parser.add_mutually_exclusive_group()
+ vm_or_device_group.add_argument(
+ '--use-vm', action='store_true',
+ help='Will run the test in the VM instead of a device.')
+ vm_or_device_group.add_argument(
+ '--device', type=str,
+ help='Hostname (or IP) of device to run the test on. This arg is not '
+ 'required if --use-vm is set.')
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('--verbose', '-v', action='store_true')
- # Required args.
- parser.add_argument(
- '--board', type=str, required=True, help='Type of CrOS device.')
- vm_or_device_group = parser.add_mutually_exclusive_group()
- vm_or_device_group.add_argument(
- '--use-vm', action='store_true',
- help='Will run the test in the VM instead of a device.')
- vm_or_device_group.add_argument(
- '--device', type=str,
- help='Hostname (or IP) of device to run the test on. This arg is not '
- 'required if --use-vm is set.')
subparsers = parser.add_subparsers(dest='test_type')
# Host-side test args.
host_cmd_parser = subparsers.add_parser(
@@ -559,13 +736,6 @@ def main():
'will be 127.0.0.1:9222.')
host_cmd_parser.set_defaults(func=host_cmd)
host_cmd_parser.add_argument(
- '--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 '
- 'to the device.')
- host_cmd_parser.add_argument(
'--deploy-chrome', action='store_true',
help='Will deploy a locally built Chrome binary to the device before '
'running the host-cmd.')
@@ -624,9 +794,12 @@ def main():
tast_test_parser.add_argument(
'--test', '-t', action='append', dest='tests',
help='A Tast test to run in the device (eg: "ui.ChromeLogin").')
+ tast_test_parser.add_argument(
+ '--use-host-tast-bin', action='store_true',
+ help='Use the host-side Tast bin to run the tests instead of the '
+ 'DUT-side local_test_runner. TODO(bpastene): Make this default.')
- add_common_args(gtest_parser)
- add_common_args(tast_test_parser)
+ add_common_args(gtest_parser, tast_test_parser, host_cmd_parser)
args, unknown_args = parser.parse_known_args()
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARN)