blob: 401b26e0ff9f0e06b333b335aac9a1111cebe295 [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from itertools import groupby
import logging
from threading import Timer
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
class firmware_FAFTSetup(FirmwareTest):
"""This test checks the following FAFT hardware requirement:
- Warm reset
- Cold reset
- Recovery boot with USB stick
- USB stick is plugged into Servo board, not DUT
- Keyboard simulation
- No terminal opened on EC console
"""
version = 1
# Delay between starting 'showkey' and pressing the keys
KEY_PRESS_DELAY = 2
def console_checker(self):
"""Verify EC console is available if using Chrome EC."""
if not self.check_ec_capability(suppress_warning=True):
# Not Chrome EC. Nothing to check.
return True
try:
self.ec.send_command("chan 0")
expected_output = ["Chip:\s+[^\r\n]*\r\n",
"RO:\s+[^\r\n]*\r\n",
"RW:\s+[^\r\n]*\r\n",
"Build:\s+[^\r\n]*\r\n"]
self.ec.send_command_get_output("version",
expected_output)
self.ec.send_command("chan 0xffffffff")
return True
except: # pylint: disable=W0702
logging.error("Cannot talk to EC console.")
logging.error(
"Please check there is no terminal opened on EC console.")
raise error.TestFail("Failed EC console check.")
def compare_key_sequence(self, actual_seq, expected_seq):
"""Comparator for key sequence captured by 'showkey'
This method compares if the last part of actual_seq matches
expected_seq. If two or more key presses in expected_seq are in a
tuple, their order are not compared. For example:
expected_seq = [a, (b, c)]
matches
actual_seq = [a, b, c] or actual_seq = [a, c, b]
This can be used to compare combo keys such as ctrl-D.
Args:
actual_seq: The actual key sequence captured by 'showkey'.
expected_seq: The expected key sequence.
"""
# Actual key sequence must be at least as long as the expected
# sequence.
expected_length = 0
for s in expected_seq:
if isinstance(s, tuple):
expected_length += len(s)
else:
expected_length += 1
if len(actual_seq) < expected_length:
return False
# We only care about the last part of actual_seq. Let's reverse both
# sequences so that we can easily compare them backward.
actual_seq.reverse()
expected_seq.reverse()
index = 0
for s in expected_seq:
if isinstance(s, tuple):
length = len(s)
actual = actual_seq[index:index + length]
actual.sort()
expected = list(s)
expected.sort()
if actual != expected:
return False
index += length
else:
if actual_seq[index] != s:
return False
index += 1
return True
def key_sequence_string(self, key_seq):
"""Get a human readable key sequence string.
Args:
key_seq: A list contains strings and/or tuple of strings.
"""
s = []
for k in key_seq:
if isinstance(k, tuple):
s.append("---Unordered---")
s.extend(k)
s.append("---------------")
else:
s.append(k)
return "\n".join(s)
def base_keyboard_checker(self, press_action, expected_output):
"""Press key and check from DUT.
Args:
press_action: A callable that would press the keys when called.
expected_output: Expected output from "showkey".
"""
# Stop UI so that key presses don't go to X.
self.faft_client.system.run_shell_command("stop ui")
# Press the keys
Timer(self.KEY_PRESS_DELAY, press_action).start()
lines = self.faft_client.system.run_shell_command_get_output("showkey")
# Turn UI back on
self.faft_client.system.run_shell_command("start ui")
# We may be getting multiple key-press or key-release.
# Let's remove duplicated items.
dup_removed = [x[0] for x in groupby(lines)]
if not self.compare_key_sequence(dup_removed, expected_output):
logging.error("Keyboard simulation not working correctly")
logging.error("Captured keycodes:\n%s", "\n".join(dup_removed))
logging.error("Expected keycodes:\n%s",
self.key_sequence_string(expected_output))
return False
logging.debug("Keyboard simulation is working correctly")
logging.debug("Captured keycodes:\n%s", "\n".join(dup_removed))
logging.debug("Expected keycodes:\n%s",
self.key_sequence_string(expected_output))
return True
def keyboard_checker(self):
"""Press 'd', Ctrl, ENTER by servo and check from DUT."""
logging.debug("keyboard_checker")
def keypress():
self.press_ctrl_d()
self.press_enter()
keys = self.faft_config.key_checker
expected_output = [
("keycode {0:x} {1}".format(keys[0][0], keys[0][1]),
"keycode {0:x} {1}".format(keys[1][0], keys[1][1])),
("keycode {0:x} {1}".format(keys[2][0], keys[2][1]),
"keycode {0:x} {1}".format(keys[3][0], keys[3][1])),
"keycode {0:x} {1}".format(keys[4][0], keys[4][1]),
"keycode {0:x} {1}".format(keys[5][0], keys[5][1])]
return self.base_keyboard_checker(keypress, expected_output)
def run_once(self):
logging.info("Check EC console is available and test warm reboot")
self.console_checker()
self.reboot_warm()
logging.info("Check test image is on USB stick and run recovery boot")
self.assert_test_image_in_usb_disk()
self.do_reboot_action(self.enable_rec_mode_and_reboot)
self.wait_fw_screen_and_plug_usb()
self.check_state((self.checkers.crossystem_checker,
{'mainfw_type': 'recovery'}))
logging.info("Check cold boot")
self.reboot_cold()
logging.info("Check keyboard simulation")
self.check_state(self.keyboard_checker)