blob: dd281e563e3d2273ee0b7dd6cede814506e3c467 [file] [log] [blame]
# Lint as: python2, python3
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Provide version control for Bluetooth tests"""
import logging
import os
from autotest_lib.client.common_lib import error
from autotest_lib.server import utils
CWD = os.getcwd()
CONNECTIVITY_DIR = os.path.dirname(__file__)
REMOTE_NAME = 'cros'
BRANCH_NAME = 'main'
BRANCH_NAME_FULL = os.path.join(REMOTE_NAME, BRANCH_NAME)
HTTP_MIRROR_URL =\
'http://commondatastorage.googleapis.com/chromeos-localmirror'
BT_BUNDLE_PATH = 'distfiles/bluetooth_peer_bundle'
WIFI_BUNDLE_PATH = 'distfiles/wifi_bundle'
LATEST_STABLE_AUTOTEST_COMMIT = 'LATEST_STABLE_AUTOTEST_COMMIT'
class Args(object):
"""An Args class for test_that"""
BOOL_DICT = {'true': True, 'false': False}
@classmethod
def get_bool(cls, arg_name, args_dict, default_value):
"""Get the bool argument value of arg_name from args_dict.
@param arg_name: the target argument to query
@param args_dict: the argument dictionary
@param default_value: the default value of the argument
if args_dict is not a dict or
if the arg_name is not in args_dict or
if the argument value is neither 'true' nor 'false'
@returns: the bool value of the target argument
"""
if type(args_dict) is dict and arg_name in args_dict:
arg_value = str(args_dict[arg_name]).lower()
return cls.BOOL_DICT.get(arg_value, default_value)
return default_value
def get_latest_stable_autotest_commit_url(phy):
""" Yield the correct API url depending on the connectivity type
as different connectivity teams may have different autotest commit pins.
@params phy: The name of the connectivity phy (e.g wifi, bluetooth).
@returns: URL string to fetch commit hash
"""
generate_commit_url = lambda bundle_url: os.path.join(
HTTP_MIRROR_URL, bundle_url, LATEST_STABLE_AUTOTEST_COMMIT)
if phy == 'bluetooth':
url = generate_commit_url(BT_BUNDLE_PATH)
elif phy == 'wifi':
url = generate_commit_url(WIFI_BUNDLE_PATH)
else:
raise error.TestError('Invalid phy provided. Got {0}. Supported phys: ' \
'WiFi, Bluetooth'.format(phy))
return url
def check_git_tree_clean():
""" Check if local directory is clear from modification
@returns: True if success, False otherwise
"""
output = utils.run('git status --porcelain')
if output.stdout != '':
logging.info(
'The Autotest directory is not clean! To perform the AVL\n'
'testing consistently, the AVL setup process will fetch\n'
'a specific commit hash from the server and check out\n'
'locally. To preserve your local changes, please commit\n'
'or stash your changes! Changes:')
logging.info(output.stdout)
return False
logging.info('Local git tree is clean.')
return True
def fetch_target_commit(phy):
""" Fetch from the cloud or git to retrieve latest ToT or latest stable
commit hash.
@params phy: The name of the connectivity phy (e.g wifi, bluetooth).
@returns: current and targeted commit hash
"""
current_commit = utils.system_output('git rev-parse HEAD')
utils.run('git fetch ' + REMOTE_NAME)
target_commit = utils.system_output(
'git rev-parse {}'.format(BRANCH_NAME_FULL))
output = utils.run('curl {}'.format(
get_latest_stable_autotest_commit_url(phy)),
ignore_status=True)
if output.exit_status != 0:
logging.info('Failed to fetch the latest commit from the server')
logging.info(output.stdout)
logging.info(output.stderr)
else:
target_commit = output.stdout.strip()
logging.info('The latest commit will be used is:\n%s', target_commit)
return current_commit, target_commit
def checkout_commit(commit):
""" Checkout the autotest directory to the specified commit."""
output = utils.run('git checkout {}'.format(commit), ignore_status=True)
if output.exit_status != 0:
logging.info(output.stderr)
logging.info('Failed to checkout target commit, please retry '
'after\nrepo sync')
else:
logging.info('Target (stable or ToT) autotest commit is checked out,\n'
'please rerun the test!')
def test_version_setup_exit_print():
""" Exit the setup and return to the previous CWD."""
logging.info('=======================================================\n')
os.chdir(CWD)
def test_version_setup(phy, args_dict={}):
"""This and above functions hope to sync the AVL test environments
among different vendors, partners, and developers by providing an
automatic process to fetch a commit hash of the "released"
(or "stabled") version of the autotest directory from the cloud and
checkout locally. No manual interaction should be expected.
@params phy: The name of the connectivity phy (e.g wifi, bluetooth).
@params args_dict: The argument dictionary passed to test_that through
--args. For example, to skip test_version_setup, one can use
the argument as
test_that --args "version_check=false" ...
@returns: True if current commit version satisfied requirement, the
test shall proceed. False otherwise.
"""
logging.info('=======================================================\n'
' AVL Test Setup\n')
if not Args.get_bool('version_check', args_dict, default_value=True):
logging.info('Skip test_version_setup() because version_check=false.')
return True
os.chdir(CONNECTIVITY_DIR)
if not check_git_tree_clean():
test_version_setup_exit_print()
return False
current_commit, target_commit = fetch_target_commit(phy)
if current_commit == target_commit:
logging.info('Local tree is already at target autotest commit.')
test_version_setup_exit_print()
return True
checkout_commit(target_commit)
test_version_setup_exit_print()
return False