xref: /aosp_15_r20/external/autotest/server/site_tests/firmware_Mosys/firmware_Mosys.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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