blob: 593867f89a83611caff4420a162be8d9e8007632 [file] [log] [blame]
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# TODO(b/339345323): Remove from PVS testplans and remove this file.
import logging
import re
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
from autotest_lib.server.cros.faft.utils.elog_verifier import ElogVerifier
class CbmemVerifier:
"""Verifier for parsing cbmem firmware log."""
def __init__(self, system, cmd):
self.entries = system.run_shell_command_get_output(cmd, True)
if not self.entries:
raise error.TestError('Failed to retrieve cbmem log by %s' % cmd)
def find_word(self, keyword=''):
"""Search for certain keyword in the whole cbmem firmware log."""
output = [line for line in self.entries if keyword in line]
logging.info('Search for %s in cbmem log, found %d matches', keyword,
len(output))
return output
class firmware_MiniDiag(FirmwareTest):
"""Servo based MiniDiag firmware boot test."""
version = 1
STORAGE_HEALTH_INFO_STR = 'Storage health info'
MEMORY_CHECK_QUICK_STR = 'Memory check (quick)'
def initialize(self, host, cmdline_args):
super(firmware_MiniDiag, self).initialize(host, cmdline_args)
if not self.menu_switcher:
raise error.TestNAError('Test skipped for menuless UI')
if not self.check_minidiag_capability():
raise error.TestNAError('MiniDiag is not enabled for this board')
self.switcher.setup_mode('normal')
self.setup_usbkey(usbkey=False)
def verify_elog_launch_count(self):
"""Verify that event log contains MiniDiag launch."""
elog_verifier = ElogVerifier(self.faft_client.system)
# Search for ELOG_DEPRECATED_TYPE_CROS_DIAGNOSTICS or
# ELOG_TYPE_FW_VBOOT_INFO of diagnostic mode
if not elog_verifier.find_events(
r'Launch Diagnostics|boot_mode=Diagnostic', 2):
raise error.TestError('No MiniDiag launch event detected')
logging.info('Event log launch count verified')
def verify_cbmem(self):
"""Verify that cbmem log contains MiniDiag data."""
cbmem_loss_msg = ' cbmem logs may be lost or incomplete'
verifier = CbmemVerifier(self.faft_client.system, 'cbmem -2')
# Verify storage health info by "<Storage health info>" or "<Storage>"
if not (verifier.find_word('<' + self.STORAGE_HEALTH_INFO_STR +
'> menu')
or verifier.find_word('<Storage> menu')):
raise error.TestError('No storage health info log found,' +
cbmem_loss_msg)
# Verify quick memory test by "<Memory check (quick)> or
# <Quick memory check>"
if not (verifier.find_word('<' + self.MEMORY_CHECK_QUICK_STR +
'> menu')
or verifier.find_word('<Quick memory check> menu')):
raise error.TestError('No quick memory test log found,' +
cbmem_loss_msg)
if verifier.find_word('Memory test failed:'):
raise error.TestError('Quick memory test failed')
output = verifier.find_word('memory_test_run_step')
fmt = re.compile(
r'([0-9]+) ms \(([0-9]+) bytes/us\) ... \(([0-9]+)%\)')
for entry in output:
# src/diag/memory.c:[line]:memory_test_run_step:[pattern_name]:
# [memory range]: state
_, _, _, _, _, state = entry.split(':')
# [loop time] ms ([speed] bytes/us) ... ([percentage]%)
_, speed, _ = fmt.search(state).groups()
if int(speed) == 0:
raise error.TestError('Memory test stuck')
logging.info('Cbmem log verified')
def _verify_elog_test_report_event(self, match, type_str, result_str):
logging.info(
'Expect an event with type=%s and result=%s...',
type_str, result_str)
if match[0].lower() != type_str.lower() or match[1] != result_str:
raise error.TestError(
'Error: got type=%s and result=%s',
match[0], match[1])
def verify_elog_test_report(self):
"""Verify that event log contains MiniDiag test report."""
elog_verifier = ElogVerifier(self.faft_client.system)
EVENT_PATTERN = 'type=([\w \(\)]+), result=(\w+), time=([\d]+m[\d]+s)'
event_pattern = re.compile(EVENT_PATTERN)
elog_events = elog_verifier.find_events(
r'Diagnostics Mode | Diagnostics Logs', 2)
if len(elog_events) != 1:
raise error.TestError(
'Expect 1 elog test report, but got %d', len(elog_events))
events = event_pattern.findall(elog_events[0])
if len(events) != 2:
raise error.TestError(
'Expect 2 events in the report, but got %d', len(events))
# Event #0 should be a passed Storage Health Info
self._verify_elog_test_report_event(
events[0], self.STORAGE_HEALTH_INFO_STR, 'Passed')
# Event #1 should be an aborted Memory Check (quick)
self._verify_elog_test_report_event(
events[1], self.MEMORY_CHECK_QUICK_STR, 'Aborted')
logging.info('Event log test report verified')
def launch_minidiag(self):
"""Launch MiniDiag, navigate, and back to the OS."""
# Trigger MiniDiag by menu navigation
logging.info('Trigger MiniDiag by menu navigation')
self.switcher.enable_rec_mode_and_reboot(usb_state='host')
self.switcher.wait_for_client_offline()
self.menu_switcher.trigger_rec_to_minidiag()
# Navigate MiniDiag
logging.info('Navigate among MiniDiag screens')
self.menu_switcher.navigate_minidiag_quick_memory_check()
self.menu_switcher.navigate_minidiag_storage()
logging.info('MiniDiag navigation finished')
def run_once(self):
"""Method which actually runs the test."""
# Check which type of reset we need
need_warm_reset = self.check_minidiag_capability(
['cbmem_preserved_by_ap_reset'])
need_power_off = self.check_minidiag_capability(
['event_log_test_report'])
# Warm reset: This preserves cbmem
# This will not trigger writing test report to event log, so we need two
# phases of MiniDiag navigation.
if need_warm_reset:
logging.info('Launch MiniDiag and leave with warm reset')
self.launch_minidiag()
self.switcher.simple_reboot(reboot_type='warm',
sync_before_boot=False)
self.switcher.wait_for_client()
# Verify logs
logging.info('Verify cbmem log for MiniDiag')
self.verify_cbmem()
else:
logging.info('Skip verifying with warm reset')
# Power off: This triggers writing test report to event log
# We should at least navigate MiniDiag once
if need_power_off or not need_warm_reset:
logging.info('Launch MiniDiag and leave with power off')
self.launch_minidiag()
self.run_shutdown_process(
shutdown_action=utils.wrapped_partial(
self.menu_switcher.power_off,
wait_for_screen=False),
post_power_action=self.switcher.wait_for_client)
# Verify logs
if need_power_off:
logging.info('Verify event log test report for MiniDiag')
self.verify_elog_test_report()
else:
logging.info('Skip verifying event log test report')
else:
logging.info('Skip verifying with power off')
# Verify event log launch count.
if self.check_minidiag_capability(['event_log_launch_count']):
logging.info('Verify event log launch count for MiniDiag')
self.verify_elog_launch_count()
else:
logging.info('Skip verifying event log launch count')