1# Copyright 2017 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"""Check USB device by running linux command on CfM""" 6 7from __future__ import print_function 8 9import logging 10import re 11import time 12import common 13from autotest_lib.client.common_lib.cros.manual import get_usb_devices 14from autotest_lib.client.common_lib.cros import cros_config 15from autotest_lib.client.common_lib.cros import power_cycle_usb_util 16 17CORE_DIR_LINES = 3 18ATRUS = '18d1:8001' 19 20def check_chrome_logfile(dut): 21 """ 22 Get the latest chrome log file. 23 @param dut: The handle of the device under test. 24 @returns: the latest chrome log file 25 """ 26 output = None 27 logging.info('---Get the latest chrome log file') 28 cmd = 'ls -latr /var/log/chrome/chrome' 29 try: 30 output = dut.run(cmd, ignore_status=True).stdout 31 except Exception as e: 32 logging.exception('Fail to run command %s.', cmd) 33 return None 34 logging.info('---cmd: %s', cmd) 35 logging.info('---output: %s', output.lower().strip()) 36 return output 37 38def check_last_reboot(dut): 39 """ 40 Get the last line of eventlog.txt 41 @param dut: The handle of the device under test. 42 @returns: the last line in eventlog.txt 43 """ 44 output = None 45 cmd = 'tail -1 /var/log/eventlog.txt' 46 logging.info('---Get the latest reboot log') 47 try: 48 output = dut.run(cmd, ignore_status=True).stdout 49 except Exception as e: 50 logging.exception('Fail to run command %s.', cmd) 51 return None 52 logging.info('---cmd: %s', cmd) 53 logging.info('---output: %s', output.lower().strip()) 54 return output 55 56def check_is_platform(dut, name): 57 """ 58 Check whether CfM is expected platform. 59 @param dut: The handle of the device under test. 60 @param name: The name of platform 61 @returns: True, if CfM's platform is same as expected. 62 False, if not. 63 """ 64 cros_config_args = '/identity platform-name' 65 output = cros_config.call_cros_config_get_output(cros_config_args, 66 dut.run, ignore_status=True) 67 logging.info('---cmd: cros_config %s', cros_config_args) 68 logging.info('---output: %s', output.lower()) 69 return output.lower() == name 70 71 72def get_mgmt_ipv4(dut): 73 """ 74 Get mgmt ipv4 address 75 @param dut: The handle of the device under test. Should be initialized in 76 autotest. 77 @return: ipv4 address for mgmt interface. 78 """ 79 cmd = 'ifconfig -a | grep eth0 -A 2 | grep netmask' 80 try: 81 output = dut.run(cmd, ignore_status=True).stdout 82 except Exception as e: 83 logging.exception('Fail to run command %s.', cmd) 84 return None 85 ipv4 = re.findall(r"inet\s*([0-9.]+)\s*netmask.*", output)[0] 86 return ipv4 87 88 89def retrieve_usb_devices(dut): 90 """ 91 Populate output of usb-devices on CfM. 92 @param dut: handle of CfM under test 93 @returns dict of all usb devices detected on CfM. 94 """ 95 usb_devices = (dut.run('usb-devices', ignore_status=True). 96 stdout.strip().split('\n\n')) 97 usb_data = get_usb_devices.extract_usb_data( 98 '\nUSB-Device\n'+'\nUSB-Device\n'.join(usb_devices)) 99 return usb_data 100 101 102def extract_peripherals_for_cfm(usb_data): 103 """ 104 Check CfM has camera, speaker and Mimo connected. 105 @param usb_data: dict extracted from output of "usb-devices" 106 """ 107 peripheral_map = {} 108 get_devices_funcs = (get_usb_devices.get_speakers, 109 get_usb_devices.get_cameras, get_usb_devices.get_display_mimo, 110 get_usb_devices.get_controller_mimo) 111 for get_devices in get_devices_funcs: 112 device_list = get_devices(usb_data) 113 for pid_vid, device_count in device_list.iteritems(): 114 if device_count > 0: 115 peripheral_map[pid_vid] = device_count 116 117 for pid_vid, device_count in peripheral_map.iteritems(): 118 logging.info('---device: %s (%s), count: %d', 119 pid_vid, get_usb_devices.get_device_prod(pid_vid), 120 device_count) 121 122 return peripheral_map 123 124 125def check_peripherals_for_cfm(peripheral_map): 126 """ 127 Check CfM has one and only one camera, 128 one and only one speaker, 129 or one and only one mimo. 130 @param peripheral_map: dict for connected camera, speaker, or mimo. 131 @returns: True if check passes, 132 False if check fails. 133 """ 134 peripherals = peripheral_map.keys() 135 136 type_camera = set(peripherals).intersection(get_usb_devices.CAMERA_LIST) 137 type_speaker = set(peripherals).intersection(get_usb_devices.SPEAKER_LIST) 138 type_controller = set(peripherals).intersection(\ 139 get_usb_devices.TOUCH_CONTROLLER_LIST) 140 type_panel = set(peripherals).intersection(\ 141 get_usb_devices.TOUCH_DISPLAY_LIST) 142 143 # check CfM have one, and only one type camera, huddly and mimo 144 if len(type_camera) == 0: 145 logging.info('No camera is found on CfM.') 146 return False 147 148 if not len(type_camera) == 1: 149 logging.info('More than one type of cameras are found on CfM.') 150 return False 151 152 if len(type_speaker) == 0: 153 logging.info('No speaker is found on CfM.') 154 return False 155 156 if not len(type_speaker) == 1: 157 logging.info('More than one type of speakers are found on CfM.') 158 return False 159 160 if len(type_controller) == 0: 161 logging.info('No controller is found on CfM.') 162 return False 163 164 165 if not len(type_controller) == 1: 166 logging.info('More than one type of controller are found on CfM.') 167 return False 168 169 if len(type_panel) == 0: 170 logging.info('No Display is found on CfM.') 171 return False 172 173 if not len(type_panel) == 1: 174 logging.info('More than one type of displays are found on CfM.') 175 return False 176 177 # check CfM have only one camera, huddly and mimo 178 for pid_vid, device_count in peripheral_map.iteritems(): 179 if device_count > 1: 180 logging.info('Number of device %s connected to CfM : %d', 181 get_usb_devices.get_device_prod(pid_vid), 182 device_count) 183 return False 184 185 return True 186 187 188def check_usb_enumeration(dut, puts): 189 """ 190 Check USB enumeration for devices 191 @param dut: the handle of CfM under test 192 @param puts: the list of peripherals under test 193 @returns True, none if test passes 194 False, errMsg if test test fails 195 """ 196 usb_data = retrieve_usb_devices(dut) 197 if not usb_data: 198 logging.warning('No usb devices found on DUT') 199 return False, 'No usb device found on DUT.' 200 else: 201 usb_device_list = extract_peripherals_for_cfm(usb_data) 202 logging.info('---usb device = %s', usb_device_list) 203 if not set(puts).issubset(set(usb_device_list.keys())): 204 logging.info('Detect device fails for usb enumeration') 205 logging.info('Expect enumerated devices: %s', puts) 206 logging.info('Actual enumerated devices: %s', 207 usb_device_list.keys()) 208 return False, 'Some usb devices are not found.' 209 return True, None 210 211 212def check_usb_interface_initializion(dut, puts): 213 """ 214 Check CfM shows valid interface for all peripherals connected. 215 @param dut: the handle of CfM under test 216 @param puts: the list of peripherals under test 217 @returns True, none if test passes 218 False, errMsg if test test fails 219 """ 220 usb_data = retrieve_usb_devices(dut) 221 for put in puts: 222 number, health = get_usb_devices.is_usb_device_ok(usb_data, put) 223 logging.info('---device interface = %d, %s for %s', 224 number, health, get_usb_devices.get_device_prod(put)) 225 if '0' in health: 226 logging.warning('Device %s has invalid interface', put) 227 return False, 'Device {} has invalid interface.'.format(put) 228 return True, None 229 230 231def clear_core_file(dut): 232 """clear core files""" 233 cmd = "rm -rf /var/spool/crash/*.*" 234 try: 235 dut.run_output(cmd) 236 except Exception as e: 237 logging.exception('Fail to clean core files under ' 238 '/var/spool/crash') 239 logging.exception('Fail to execute %s :', cmd) 240 241 242def check_process_crash(dut, cdlines): 243 """Check whether there is core file.""" 244 cmd = 'ls -latr /var/spool/crash' 245 try: 246 core_files_output = dut.run_output(cmd).splitlines() 247 except Exception as e: 248 logging.exception('Can not find file under /var/spool/crash.') 249 logging.exception('Fail to execute %s:', cmd) 250 return True, CORE_DIR_LINES 251 logging.info('---%s\n---%s', cmd, core_files_output) 252 if len(core_files_output) - cdlines <= 0: 253 logging.info('---length of files: %d', len(core_files_output)) 254 return True, len(core_files_output) 255 else: 256 return False, len(core_files_output) 257 258 259def gpio_usb_test(dut, gpio_list, device_list, pause, board): 260 """ 261 Run GPIO test to powercycle usb port. 262 @parama dut: handler of CfM, 263 @param gpio_list: the list of gpio ports, 264 @param device_list: the list of usb devices, 265 @param pause: time needs to wait before restoring power to usb port, 266 in seconds 267 @param board: board name for CfM 268 @returns True 269 """ 270 for device in device_list: 271 vid, pid = device.split(':') 272 logging.info('---going to powercyle device %s:%s', vid, pid) 273 try: 274 power_cycle_usb_util.power_cycle_usb_vidpid(dut, board, 275 vid, pid, pause) 276 except Exception as e: 277 errmsg = 'Fail to power cycle device.' 278 logging.exception('%s.', errmsg) 279 return False, errmsg 280 281 return True, None 282 283 284def reboot_test(dut, pause): 285 """ 286 Reboot CfM. 287 @parama dut: handler of CfM, 288 @param pause: time needs to wait after issuing reboot command, in seconds, 289 290 """ 291 try: 292 dut.reboot() 293 except Exception as e: 294 logging.exception('Fail to reboot CfM.') 295 return False 296 logging.info('---reboot done') 297 time.sleep(pause) 298 return True 299 300 301 302def find_last_log(dut, speaker): 303 """ 304 Get the lastlast_lines line for log files. 305 @param dut: handler of CfM 306 @param speaker: vidpid if speaker. 307 @returns: the list of string of the last line of logs. 308 """ 309 last_lines = { 310 'messages':[], 311 'chrome':[], 312 'ui': [], 313 'atrus': [] 314 } 315 logging.debug('Get the last line of log file, speaker %s', speaker) 316 try: 317 cmd = "tail -1 /var/log/messages | awk -v N=1 '{print $N}'" 318 last_lines['messages'] = dut.run_output(cmd).strip().split()[0] 319 cmd = "tail -1 /var/log/chrome/chrome | awk -v N=1 '{print $N}'" 320 last_lines['chrome'] = dut.run_output(cmd).strip().split()[0] 321 cmd = "tail -1 /var/log/ui/ui.LATEST | awk -v N=1 '{print $N}'" 322 last_lines['ui']= dut.run_output(cmd) 323 if speaker == ATRUS and check_is_platform(dut, 'guado'): 324 logging.info('---atrus speaker %s connected to CfM', speaker) 325 cmd = 'tail -1 /var/log/atrus.log | awk -v N=1 "{print $N}"' 326 last_lines['atrus'] = dut.run_output(cmd).strip().split()[0] 327 except Exception as e: 328 logging.exception('Fail to get the last line from log files.') 329 for item, timestamp in last_lines.iteritems(): 330 logging.debug('---%s: %s', item, timestamp) 331 return last_lines 332 333 334def collect_log_since_last_check(dut, lastlines, logfile): 335 """Collect log file since last check.""" 336 output = None 337 if logfile == "messages": 338 cmd ='awk \'/{}/,0\' /var/log/messages'.format(lastlines[logfile]) 339 if logfile == "chrome": 340 cmd ='awk \'/{}/,0\' /var/log/chrome/chrome'.format(lastlines[logfile]) 341 if logfile == "ui": 342 cmd ='awk \'/{}/,0\' /var/log/ui/ui.LATEST'.format(lastlines[logfile]) 343 if logfile == 'atrus': 344 cmd ='awk \'/{}/,0\' /var/log/atrus.log'.format(lastlines[logfile]) 345 logging.info('---cmd = %s', cmd) 346 try: 347 output = dut.run_output(cmd).split('\n') 348 except Exception as e: 349 logging.exception('Fail to get output from log files.') 350 logging.info('---length of log: %d', len(output)) 351 if not output: 352 logging.info('--fail to find match log, check the latest log.') 353 354 if not output: 355 if logfile == "messages": 356 cmd ='cat /var/log/messages' 357 if logfile == "chrome": 358 cmd ='cat /var/log/chrome/chrome' 359 if logfile == "ui": 360 cmd ='cat /var/log/ui/ui.LATEST' 361 if logfile == 'atrus': 362 cmd ='cat /var/log/atrus.log' 363 output = dut.run_output(cmd).split('\n') 364 logging.info('---length of log: %d', len(output)) 365 return output 366 367def check_log(dut, timestamp, error_list, checkitem, logfile): 368 """ 369 Check logfile does not contain any element in error_list[checkitem]. 370 """ 371 error_log_list = [] 372 logging.info('---now check log %s in file %s', checkitem, logfile) 373 output = collect_log_since_last_check(dut, timestamp, logfile) 374 for _error in error_list[checkitem]: 375 error_log_list.extend([s for s in output if _error in str(s)]) 376 if not error_log_list: 377 return True, None 378 else: 379 tempmsg = '\n'.join(error_log_list) 380 errmsg = 'Error_Found:in_log_file:{}:{}.'.format(logfile, tempmsg) 381 logging.info('---%s', errmsg) 382 return False, errmsg 383