1# Copyright 2019 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5""" 6Test which updates chameleond on the Bluetooth Peer device 7 8This is not a test per se. This 'test' checks if the chameleond version on the 9Bluetooth peer device and updates it if it below the expected value. 10 11""" 12 13 14import logging 15import os 16import sys 17import time 18 19from datetime import datetime 20 21from autotest_lib.client.common_lib import error 22from autotest_lib.server import test 23 24 25# The current chameleond version 26CUR_BT_PKG_VERSION='0.0.1' 27 28 29# The following needs to be kept in sync with values chameleond code 30BUNDLE='chameleond-0.0.2.tar.gz' # Name of the chamleond package 31BUNDLE_DIR = 'chameleond-0.0.2' 32BUNDLE_VERSION = '9999' 33CHAMELEON_BOARD = 'fpga_tio' 34 35def run_cmd(peer, cmd): 36 """A wrapper around host.run().""" 37 try: 38 logging.info("executing command %s on peer",cmd) 39 result = peer.host.run(cmd) 40 logging.info("exit_status is %s", result.exit_status) 41 logging.info("stdout is %s stderr is %s", result.stdout, result.stderr) 42 output = result.stderr if result.stderr else result.stdout 43 if result.exit_status == 0: 44 return True, output 45 else: 46 return False, output 47 except error.AutoservRunError as e: 48 logging.error("Error while running cmd %s %s", cmd, e) 49 return False, None 50 51 52def cmp_version(v1,v2): 53 """ Compare versions. 54 55 Return -1,0,1 depending on whether v1 is less than, equal to or greater 56 than v2 57 58 """ 59 p1 = [int(i) for i in v1.split('.')] 60 p2 = [int(i) for i in v2.split('.')] 61 for i1,i2 in zip(p1,p2): 62 if i1 < i2: 63 return -1 64 elif i1 > i2: 65 return 1 66 else: 67 continue 68 return 0 69 70 71def check_version_format(v): 72 """ Check whether version is in proper format""" 73 try: 74 parts = v.split('.') 75 if len(parts) != 3: 76 logging.error('version should be in format x.x.x') 77 return False 78 return all([i.isdigit() for i in parts]) 79 except Exception as e: 80 logging.error('exception in check_version_format %s', str(e)) 81 return False 82 83 84def is_update_needed(peer): 85 """ Check if update is required 86 87 Get the version of chameleond on the peer and compare to 88 expected version 89 90 @returns: True/False 91 """ 92 try: 93 version = peer.get_bt_pkg_version() 94 except: 95 logging.error("Getting the version failed %s",sys.exc_info()) 96 raise error.TestFail("Unable to get version") 97 98 logging.info("version on chameleond on the peer device is %s", version) 99 logging.info("current chameleond version is %s", CUR_BT_PKG_VERSION) 100 101 if not check_version_format(version): 102 logging.error("Version not in proper format") 103 raise error.TestFail("Version not in proper format") 104 105 if cmp_version(version, CUR_BT_PKG_VERSION) == -1: 106 logging.debug("Current version is lower. Update required") 107 return True 108 elif cmp_version(version, CUR_BT_PKG_VERSION) == 0: 109 logging.debug("Current version is equal. Update not required") 110 return False 111 else: 112 # A lab peer with a higher version should be highlighted 113 raise error.TestFail("Peer has a higher version") 114 115 116def is_tmp_noexec(peer): 117 """Check if /tmp partition is not excutable.""" 118 try: 119 cmd = 'cat /proc/mounts |grep "/tmp"' 120 status, output = run_cmd(peer, cmd) 121 return status and 'noexec' in output 122 except Exception as e: 123 logging.error('Exception %s while checking status of /tmp', str(e)) 124 return True 125 126def remount_tmp_exec(peer): 127 """Remount /tmp partition with exec flag.""" 128 try: 129 cmd = 'mount -o remount,exec "/tmp"' 130 status, output = run_cmd(peer, cmd) 131 return status 132 except Exception as e: 133 logging.error('Exception %s while remounting /tmp', str(e)) 134 return False 135 136 137 138def perform_update(peer, arch): 139 """ Update the chameleond on the peer""" 140 141 if arch == 'CHROMEOS': 142 logging.info("Check if /tmp partition is executable") 143 if is_tmp_noexec(peer): 144 if not remount_tmp_exec(peer): 145 logging.error("unable to remount /tmp as exec") 146 return False 147 if is_tmp_noexec(peer): 148 logging.error("/tmp partition is still noexec") 149 return False 150 logging.info("/tmp partition is executable") 151 152 153 logging.info("copy the file over to the peer") 154 try: 155 current_dir = os.path.dirname(os.path.realpath(__file__)) 156 bundle_path = os.path.join(current_dir, BUNDLE) 157 logging.debug("package location is %s", bundle_path) 158 peer.host.send_file(bundle_path, '/tmp/') 159 except: 160 logging.error("copying the file failed %s ", sys.exc_info()) 161 return False 162 163 HOST_NOW = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') 164 logging.info("running make on peer") 165 cmd = ('cd /tmp && rm -rf %s && tar zxf %s &&' 166 'cd %s && find -exec touch -c {} \; &&' 167 'make install REMOTE_INSTALL=TRUE ' 168 'HOST_NOW="%s" BUNDLE_VERSION=%s ' 169 'CHAMELEON_BOARD=%s') % (BUNDLE_DIR, BUNDLE, BUNDLE_DIR, 170 HOST_NOW, BUNDLE_VERSION, 171 CHAMELEON_BOARD) 172 status, _ = run_cmd(peer, cmd) 173 if not status: 174 logging.info("make failed") 175 return False 176 177 logging.info("chameleond installed on peer") 178 return True 179 180 181 182def restart_check_chameleond(peer, arch): 183 """restart chamleond and make sure it is running.""" 184 def _check_output(output, arch): 185 logging.info("checking output '%s' on %s", output, arch) 186 if arch == 'CHROMEOS': 187 expected_output = 'chameleond start/running' 188 else: 189 expected_output = 'chameleond is running' 190 return expected_output in output 191 192 if arch == 'CHROMEOS': 193 restart_cmd = 'restart chameleond' 194 start_cmd = 'start chameleond' 195 status_cmd = 'status chameleond' 196 else: 197 restart_cmd = 'sudo /etc/init.d/chameleond restart' 198 start_cmd = 'sudo /etc/init.d/chameleond start' 199 status_cmd = 'sudo /etc/init.d/chameleond status' 200 201 status, _ = run_cmd(peer, restart_cmd) 202 if not status: 203 status, _ = run_cmd(peer, start_cmd) 204 if not status: 205 logging.error("restarting/starting chamleond failed") 206 207 # Wait till chameleond initialization is complete 208 time.sleep(5) 209 210 status, output = run_cmd(peer, status_cmd) 211 return status and _check_output(output, arch) 212 213 214 215def update_peer(host): 216 """Update the chameleond on peer device if requried""" 217 218 if host.chameleon is None: 219 raise error.TestError('Bluetooth Peer not present') 220 221 peer = host.chameleon 222 arch = host.chameleon.get_platform() 223 224 if arch not in ['CHROMEOS', 'RASPI']: 225 raise error.TestNAError("%s architecture not supported" % arch) 226 227 if not is_update_needed(peer): 228 raise error.TestNAError("Update not needed") 229 230 if not perform_update(peer, arch): 231 raise error.TestFail("Update failed") 232 233 if not restart_check_chameleond(peer, arch): 234 raise error.TestFail("Unable to start chameleond") 235 236 if is_update_needed(peer): 237 raise error.TestFail("Version not updated after upgrade") 238 239 logging.info("updating chameleond succeded") 240 241 242 243class bluetooth_PeerUpdate(test.test): 244 """ 245 This test updates chameleond on Bluetooth peer devices 246 247 """ 248 249 version = 1 250 251 def run_once(self, host): 252 """ Update Bluetooth peer device 253 254 @param host: the DUT, usually a chromebook 255 """ 256 257 self.host = host 258 update_peer(self.host) 259