136 lines
4.7 KiB
Python
Executable File
136 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright 2019 The Chromium Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
"""Custom swarming trigger script for ChromeOS device tests.
|
|
|
|
CrOS device tests are unique in that the device OS they prefer to run on is
|
|
continuously changing. The LKGM file, checked into src at
|
|
//chromeos/CHROMEOS_LKGM, represents the ChromeOS version Chrome's ToT aims
|
|
to be compatible with. Therefore, a CrOS test for Chrome ideally targets a
|
|
device running the LKGM.
|
|
|
|
Since the LKGM file gets updated frequently (~daily), we can't reasonably
|
|
hardcode the LKGM in the test specs. So this special trigger script will read
|
|
the current LKGM (at the time of trigger) and append that to the task's
|
|
dimensions. If such a device isn't available in time, the task will fallback
|
|
to one running any OS.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
import base_test_triggerer
|
|
|
|
SRC_DIR = os.path.dirname(
|
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
LKGM_FILE_PATH = os.path.join(SRC_DIR, 'chromeos', 'CHROMEOS_LKGM')
|
|
# Should match something that looks like "12345.0.0".
|
|
LKGM_RE = re.compile(r'\d+\.\d+\.\d+')
|
|
PRIMARY_SLICE_EXPIRATION_S = 300
|
|
|
|
|
|
def read_current_lkgm():
|
|
if not os.path.exists(LKGM_FILE_PATH):
|
|
sys.stderr.write('LKGM file not present at %s\n' % LKGM_FILE_PATH)
|
|
return None
|
|
|
|
with open(LKGM_FILE_PATH) as f:
|
|
lkgm = f.read().strip()
|
|
|
|
if not LKGM_RE.match(lkgm):
|
|
sys.stderr.write('Unknown format of LKGM: %s\n' % lkgm)
|
|
return None
|
|
|
|
# Just the major version should be sufficient.
|
|
return lkgm.split('.')[0]
|
|
|
|
|
|
def parse_args(triggerer):
|
|
# This script will do nothing but inspect and tweak the dimension args to
|
|
# `swarming.py trigger`. So let's pull just those out.
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
'-d',
|
|
'--dimension',
|
|
default=[],
|
|
action='append',
|
|
nargs=2,
|
|
dest='dimensions',
|
|
help=
|
|
'Dimensions to filter on. Duplicated from the `swarming.py trigger` '
|
|
'command. Parsed here to ensure `device_os` is not added.')
|
|
parser.add_argument(
|
|
'--optional-dimension',
|
|
default=[],
|
|
action='append',
|
|
nargs=3,
|
|
dest='optional_dimensions',
|
|
help='Optional dimensions which will result in additional task slices. '
|
|
'Duplicated from the `swarming.py trigger` command.')
|
|
base_test_triggerer.BaseTestTriggerer.setup_parser_contract(parser)
|
|
args, additional_args = parser.parse_known_args()
|
|
additional_args = triggerer.modify_args(additional_args, 0,
|
|
args.shard_index, args.shards,
|
|
args.dump_json)
|
|
|
|
if additional_args[0] != 'trigger':
|
|
parser.error(
|
|
'This script is only supported for `swarming.py trigger`'
|
|
' invocations.'
|
|
)
|
|
|
|
for k, _ in args.dimensions:
|
|
if k == 'device_os':
|
|
parser.error(
|
|
'Must not specify the device_os dimension when using this'
|
|
' script. (It will be added automatically.)')
|
|
|
|
# It might be a valid use-case to include optional-dimensions in the initial
|
|
# invocation. But it'd be difficult to integrate them into what we're doing
|
|
# here. So let's just ensure there aren't any.
|
|
if args.optional_dimensions:
|
|
parser.error(
|
|
'Must not specify optional dimensions when using this script.')
|
|
|
|
return args, additional_args
|
|
|
|
|
|
def main():
|
|
triggerer = base_test_triggerer.BaseTestTriggerer()
|
|
args, additional_args = parse_args(triggerer)
|
|
|
|
current_lkgm = read_current_lkgm()
|
|
if not current_lkgm:
|
|
return 1
|
|
|
|
new_args = additional_args[:1]
|
|
# Insert our modified dimension args in between the 1st and 2nd args of the
|
|
# initial `swarming.py` invocation. This avoids the presence of the special
|
|
# `--` arg from causing swarming.py to ignore them.
|
|
needs_device_status = True
|
|
for k, v in args.dimensions:
|
|
new_args.extend(['--dimension', k, v])
|
|
if k == 'device_status':
|
|
needs_device_status = False
|
|
|
|
# Only CrOS device bots with a device_status dimension of "available" should
|
|
# run tests. So target those explicitly if we aren't already.
|
|
if needs_device_status:
|
|
new_args.extend(['--dimension', 'device_status', 'available'])
|
|
|
|
new_args.extend([
|
|
'-optional-dimension',
|
|
'device_os=%s:%d' % (current_lkgm, PRIMARY_SLICE_EXPIRATION_S),
|
|
])
|
|
new_args += additional_args[1:]
|
|
|
|
return triggerer.run_swarming_go(new_args, args.dump_json,
|
|
args.shard_index or 0, args.shards)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|