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