1# Copyright (c) 2014 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 5import logging 6import re 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.common_lib import utils 10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 11 12 13class firmware_Mosys(FirmwareTest): 14 """ 15 Mosys commands test for Firmware values. 16 17 Execute 18 * mosys -k ec info 19 * mosys platform name 20 * mosys -k pd info 21 22 """ 23 version = 1 24 25 26 def initialize(self, host, cmdline_args, dev_mode=False): 27 # Parse arguments from command line 28 dict_args = utils.args_to_dict(cmdline_args) 29 super(firmware_Mosys, self).initialize(host, cmdline_args) 30 self.switcher.setup_mode('dev' if dev_mode else 'normal', 31 allow_gbb_force=True) 32 # a list contain failed execution. 33 self.failed_command = [] 34 # Get a list of available mosys commands. 35 lines = self.run_cmd('mosys help') 36 self.command_list = [] 37 cmdlist_start = False 38 for line in lines: 39 if cmdlist_start: 40 cmdlst = re.split('\s+', line) 41 if len(cmdlst) > 2: 42 self.command_list.append(cmdlst[1]) 43 elif 'Commands:' in line: 44 cmdlist_start = True 45 logging.info('Available commands: %s', ' '.join(self.command_list)) 46 47 def check_for_errors(self, output, command): 48 """ 49 Check for known errors. 50 1. Bad system call (core dumped) 51 We see this a lot now that mosys is in a minijail. Even if we see 52 this error, mosys will return success, so we need to check stderr. 53 """ 54 for line in output: 55 if "Bad system call" in line: 56 logging.info("ERROR: Bad system call detected when calling mosys!") 57 self._tag_failure(command) 58 return 1 59 return 0 60 61 def run_cmd(self, command): 62 """ 63 Log and execute command and return the output. 64 65 @param command: Command to execution device. 66 @returns the output of command. 67 68 """ 69 logging.info('Execute %s', command) 70 output = self.faft_client.system.run_shell_command_get_output( 71 command, True) 72 logging.info('Output %s', output) 73 return output 74 75 def check_ec_version(self, command, exp_ec_version): 76 """ 77 Compare output of 'ectool version' for the current firmware 78 copy to exp_ec_version. 79 80 @param command: command string 81 @param exp_ec_version: The expected EC version string. 82 83 """ 84 lines = self.run_cmd('ectool version') 85 fwcopy_pattern = re.compile('Firmware copy: (.*)$') 86 ver_pattern = re.compile('(R[OW]) version: (.*)$') 87 version = {} 88 for line in lines: 89 ver_matched = ver_pattern.match(line) 90 if ver_matched: 91 version[ver_matched.group(1)] = ver_matched.group(2) 92 fwcopy_matched = fwcopy_pattern.match(line) 93 if fwcopy_matched: 94 fwcopy = fwcopy_matched.group(1) 95 if fwcopy in version: 96 actual_version = version[fwcopy] 97 logging.info('Expected ec version %s actual_version %s', 98 exp_ec_version, actual_version) 99 if exp_ec_version != actual_version: 100 self._tag_failure(command) 101 else: 102 self._tag_failure(command) 103 logging.error('Failed to locate version from ectool') 104 105 def check_pd_version(self, command, exp_pd_version): 106 """ 107 Compare output of 'ectool --dev 1 version' for the current PD firmware 108 copy to exp_pd_version. 109 110 @param command: command string 111 @param exp_pd_version: The expected PD version string. 112 113 """ 114 lines = self.run_cmd('ectool --dev 1 version') 115 fwcopy_pattern = re.compile('Firmware copy: (.*)$') 116 ver_pattern = re.compile('(R[OW]) version: (.*)$') 117 version = {} 118 for line in lines: 119 ver_matched = ver_pattern.match(line) 120 if ver_matched: 121 version[ver_matched.group(1)] = ver_matched.group(2) 122 fwcopy_matched = fwcopy_pattern.match(line) 123 if fwcopy_matched: 124 fwcopy = fwcopy_matched.group(1) 125 if fwcopy in version: 126 actual_version = version[fwcopy] 127 logging.info('Expected pd version %s actual_version %s', 128 exp_pd_version, actual_version) 129 if exp_pd_version != actual_version: 130 self._tag_failure(command) 131 else: 132 self._tag_failure(command) 133 logging.error('Failed to locate version from ectool') 134 135 def _tag_failure(self, cmd): 136 self.failed_command.append(cmd) 137 logging.error('Execute %s failed', cmd) 138 139 def run_once(self, dev_mode=False): 140 """Runs a single iteration of the test.""" 141 # mosys -k ec info 142 command = 'mosys -k ec info' 143 if self.faft_config.chrome_ec: 144 output = self.run_cmd(command) 145 self.check_for_errors(output, command) 146 p = re.compile( 147 'vendor="[A-Z]?[a-z]+" name="[ -~]+" fw_version="(.*)"') 148 v = p.match(output[0]) 149 if v: 150 version = v.group(1) 151 self.check_ec_version(command, version) 152 else: 153 self._tag_failure(command) 154 else: 155 logging.info('Skip "%s", command not available.', command) 156 157 # mosys platform name 158 command = 'mosys platform name' 159 output = self.run_cmd(command) 160 self.check_for_errors(output, command) 161 162 # mosys -k pd info 163 command = 'mosys -k pd info' 164 if self.faft_config.chrome_usbpd and 'pd' in self.command_list: 165 output = self.run_cmd(command) 166 self.check_for_errors(output, command) 167 p = re.compile('vendor="[a-z]+" name="[ -~]+" fw_version="(.*)"') 168 v = p.match(output[0]) 169 if v: 170 version = v.group(1) 171 self.check_pd_version(command, version) 172 else: 173 self._tag_failure(command) 174 else: 175 logging.info('Skip "%s", command not available.', command) 176 177 # mosys -k memory spd print all (check no error output) 178 command = 'mosys -k memory spd print all' 179 output = self.run_cmd(command) 180 self.check_for_errors(output, command) 181 p = re.compile('^dimm=".*$') 182 # Each line should start with "dimm=". 183 for i in output: 184 if not p.match(i): 185 logging.error('output does not start with dimm=%s', i) 186 self._tag_failure(command) 187 break 188 189 # Add any other mosys commands or tests before this section. 190 # empty failed_command indicate all passed. 191 if self.failed_command: 192 raise error.TestFail( 193 '%d commands failed, detail above. ' 194 'Failed commands are "%s"' % 195 (len(self.failed_command), ','.join(self.failed_command))) 196