# Copyright 2019 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """ Test which updates chameleond on the Bluetooth Peer device This is not a test per se. This 'test' checks if the chameleond version on the Bluetooth peer device and updates it if it below the expected value. """ import logging import os import sys import time from datetime import datetime from autotest_lib.client.common_lib import error from autotest_lib.server import test # The current chameleond version CUR_BT_PKG_VERSION='0.0.1' # The following needs to be kept in sync with values chameleond code BUNDLE='chameleond-0.0.2.tar.gz' # Name of the chamleond package BUNDLE_DIR = 'chameleond-0.0.2' BUNDLE_VERSION = '9999' CHAMELEON_BOARD = 'fpga_tio' def run_cmd(peer, cmd): """A wrapper around host.run().""" try: logging.info("executing command %s on peer",cmd) result = peer.host.run(cmd) logging.info("exit_status is %s", result.exit_status) logging.info("stdout is %s stderr is %s", result.stdout, result.stderr) output = result.stderr if result.stderr else result.stdout if result.exit_status == 0: return True, output else: return False, output except error.AutoservRunError as e: logging.error("Error while running cmd %s %s", cmd, e) return False, None def cmp_version(v1,v2): """ Compare versions. Return -1,0,1 depending on whether v1 is less than, equal to or greater than v2 """ p1 = [int(i) for i in v1.split('.')] p2 = [int(i) for i in v2.split('.')] for i1,i2 in zip(p1,p2): if i1 < i2: return -1 elif i1 > i2: return 1 else: continue return 0 def check_version_format(v): """ Check whether version is in proper format""" try: parts = v.split('.') if len(parts) != 3: logging.error('version should be in format x.x.x') return False return all([i.isdigit() for i in parts]) except Exception as e: logging.error('exception in check_version_format %s', str(e)) return False def is_update_needed(peer): """ Check if update is required Get the version of chameleond on the peer and compare to expected version @returns: True/False """ try: version = peer.get_bt_pkg_version() except: logging.error("Getting the version failed %s",sys.exc_info()) raise error.TestFail("Unable to get version") logging.info("version on chameleond on the peer device is %s", version) logging.info("current chameleond version is %s", CUR_BT_PKG_VERSION) if not check_version_format(version): logging.error("Version not in proper format") raise error.TestFail("Version not in proper format") if cmp_version(version, CUR_BT_PKG_VERSION) == -1: logging.debug("Current version is lower. Update required") return True elif cmp_version(version, CUR_BT_PKG_VERSION) == 0: logging.debug("Current version is equal. Update not required") return False else: # A lab peer with a higher version should be highlighted raise error.TestFail("Peer has a higher version") def is_tmp_noexec(peer): """Check if /tmp partition is not excutable.""" try: cmd = 'cat /proc/mounts |grep "/tmp"' status, output = run_cmd(peer, cmd) return status and 'noexec' in output except Exception as e: logging.error('Exception %s while checking status of /tmp', str(e)) return True def remount_tmp_exec(peer): """Remount /tmp partition with exec flag.""" try: cmd = 'mount -o remount,exec "/tmp"' status, output = run_cmd(peer, cmd) return status except Exception as e: logging.error('Exception %s while remounting /tmp', str(e)) return False def perform_update(peer, arch): """ Update the chameleond on the peer""" if arch == 'CHROMEOS': logging.info("Check if /tmp partition is executable") if is_tmp_noexec(peer): if not remount_tmp_exec(peer): logging.error("unable to remount /tmp as exec") return False if is_tmp_noexec(peer): logging.error("/tmp partition is still noexec") return False logging.info("/tmp partition is executable") logging.info("copy the file over to the peer") try: current_dir = os.path.dirname(os.path.realpath(__file__)) bundle_path = os.path.join(current_dir, BUNDLE) logging.debug("package location is %s", bundle_path) peer.host.send_file(bundle_path, '/tmp/') except: logging.error("copying the file failed %s ", sys.exc_info()) return False HOST_NOW = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') logging.info("running make on peer") cmd = ('cd /tmp && rm -rf %s && tar zxf %s &&' 'cd %s && find -exec touch -c {} \; &&' 'make install REMOTE_INSTALL=TRUE ' 'HOST_NOW="%s" BUNDLE_VERSION=%s ' 'CHAMELEON_BOARD=%s') % (BUNDLE_DIR, BUNDLE, BUNDLE_DIR, HOST_NOW, BUNDLE_VERSION, CHAMELEON_BOARD) status, _ = run_cmd(peer, cmd) if not status: logging.info("make failed") return False logging.info("chameleond installed on peer") return True def restart_check_chameleond(peer, arch): """restart chamleond and make sure it is running.""" def _check_output(output, arch): logging.info("checking output '%s' on %s", output, arch) if arch == 'CHROMEOS': expected_output = 'chameleond start/running' else: expected_output = 'chameleond is running' return expected_output in output if arch == 'CHROMEOS': restart_cmd = 'restart chameleond' start_cmd = 'start chameleond' status_cmd = 'status chameleond' else: restart_cmd = 'sudo /etc/init.d/chameleond restart' start_cmd = 'sudo /etc/init.d/chameleond start' status_cmd = 'sudo /etc/init.d/chameleond status' status, _ = run_cmd(peer, restart_cmd) if not status: status, _ = run_cmd(peer, start_cmd) if not status: logging.error("restarting/starting chamleond failed") # Wait till chameleond initialization is complete time.sleep(5) status, output = run_cmd(peer, status_cmd) return status and _check_output(output, arch) def update_peer(host): """Update the chameleond on peer device if requried""" if host.chameleon is None: raise error.TestError('Bluetooth Peer not present') peer = host.chameleon arch = host.chameleon.get_platform() if arch not in ['CHROMEOS', 'RASPI']: raise error.TestNAError("%s architecture not supported" % arch) if not is_update_needed(peer): raise error.TestNAError("Update not needed") if not perform_update(peer, arch): raise error.TestFail("Update failed") if not restart_check_chameleond(peer, arch): raise error.TestFail("Unable to start chameleond") if is_update_needed(peer): raise error.TestFail("Version not updated after upgrade") logging.info("updating chameleond succeded") class bluetooth_PeerUpdate(test.test): """ This test updates chameleond on Bluetooth peer devices """ version = 1 def run_once(self, host): """ Update Bluetooth peer device @param host: the DUT, usually a chromebook """ self.host = host update_peer(self.host)