blob: 3feda32c8bd719150caa16a7ba3c18c636926137 [file] [log] [blame]
# Copyright (c) 2013 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.
"""Uses ectool to control the onboard LED light, and lets either operator
or SMT fixture confirm LED functionality."""
import logging
import random
import time
import unittest
import factory_common # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.device import led as led_module
from cros.factory.test import factory_task
from cros.factory.test.i18n import _
from cros.factory.test.i18n import test_ui as i18n_test_ui
# The right BFTFixture module is dynamically imported based on args.bft_fixture.
# See setUp() for more detail.
from cros.factory.test.fixture import bft_fixture
from cros.factory.test import test_ui
from cros.factory.test import ui_templates
from cros.factory.utils.arg_utils import Arg
_TEST_TITLE = i18n_test_ui.MakeI18nLabel('LED Test')
# True to test all colors regardless of failure.
_FAIL_LATER = True
_SHOW_RESULT_SECONDS = 0.5
LEDColor = led_module.LED.Color
LEDIndex = led_module.LED.Index
_COLOR_LABEL = {
LEDColor.YELLOW: _('yellow'),
LEDColor.GREEN: _('green'),
LEDColor.RED: _('red'),
LEDColor.WHITE: _('white'),
LEDColor.BLUE: _('blue'),
LEDColor.AMBER: _('amber'),
LEDColor.OFF: _('off')}
_INDEX_LABEL = {
None: _('LED'),
LEDIndex.POWER: _('power LED'),
LEDIndex.BATTERY: _('battery LED'),
LEDIndex.ADAPTER: _('adapter LED')}
# Hash values are: (LED color, readable text color).
_COLOR_CODE = {
LEDColor.YELLOW: ('#ffff00', 'black'),
LEDColor.GREEN: ('#00ff00', 'black'),
LEDColor.RED: ('#ff0000', 'black'),
LEDColor.WHITE: ('#ffffff', 'black'),
LEDColor.BLUE: ('#0000ff', 'white'),
LEDColor.AMBER: ('#ffbf00', 'black'),
LEDColor.OFF: ('#000000', 'white')}
_JS_OP_RESPONSE = """
function UpdateResult(result) {
res = $('result');
if (result) {
res.innerHTML = '<span class="result-pass">PASS</span>';
} else {
res.innerHTML = '<span class="result-fail">FAIL</span>';
}
}
"""
_SELECT_COLOR_EVENT = 'led-select-color'
_HTML_KEY_TEMPLATE = """
<span class="led-btn" style="background-color: %s; color: %s"
onclick="window.test.sendTestEvent('%s', %d);">%d</span>
"""
_HTML_RESULT = (
'<div class="result-line">' +
i18n_test_ui.MakeI18nLabel('Result: ') +
'<span id="result"></span></div>')
_CSS = """
.sub-title {
font-size: 200%;
font-weight: bold;
line-height: 100px;
}
.led-btn {
display: inline-block;
width: 50px;
height: 50px;
line-height: 50px;
font-size: 200%;
padding: 5px;
margin: 3px;
border-radius: 3px;
font-weight: bold;
border: 1px solid #7D7D7D;
}
strong {
background: #ccc;
padding: 3px 6px;
margin: 0 2px;
font-weight: normal;
}
.result-line {
margin-top: 30px;
}
.result-pass {
color: green;
font-weight: bold;
}
.result-fail {
color: red;
font-weight: bold;
}
"""
class CheckLEDTask(factory_task.InteractiveFactoryTask):
"""An InteractiveFactoryTask that asks operator to check LED color.
Args:
ui: test_ui.UI instance.
template: ui_templates.OneSection instance.
led: dut.led.LED instance to control LED.
nth: The number of task.
color: LEDColor to inspect.
color_label: Label for inspected color.
index: Target LED to inspect. None means default LED.
index_label: Label for inspected index.
"""
def __init__(self, ui, template, led, nth, color, color_label,
index, index_label):
super(CheckLEDTask, self).__init__(ui)
self._template = template
self._led = led
self._nth = nth
self._color = color
self._color_label = color_label
self._index = index
self._index_label = index_label
def Run(self):
"""Lights LED in color and asks operator to verify it."""
self._InitUI()
if self._index is None:
self._led.SetColor(self._color)
else:
self._led.SetColor(self._color, led_name=self._index)
def _InitUI(self):
"""Sets instructions and binds pass/fail key."""
raise NotImplementedError
def Cleanup(self):
"""Turns the light off after the test."""
if self._index is None:
self._led.SetColor(LEDColor.OFF)
else:
self._led.SetColor(LEDColor.OFF, led_name=self._index)
class CheckLEDTaskNormal(CheckLEDTask):
"""Checks for LED colors by asking operator to push ENTER."""
def __init__(self, ui, template, led, nth, color, color_label,
index, index_label):
super(CheckLEDTaskNormal, self).__init__(
ui, template, led, nth, color, color_label, index, index_label)
def _InitUI(self):
if self._color == LEDColor.OFF:
instruction = i18n_test_ui.MakeI18nLabel(
'If the <strong>{name}</strong> is <strong>off</strong>, '
'press ENTER.', name=self._index_label)
else:
instruction = i18n_test_ui.MakeI18nLabel(
'If the <strong>{name}</strong> lights up in '
'<strong>{color}</strong>, press ENTER.',
name=self._index_label, color=self._color_label)
self._ui.AppendCSS(_CSS)
self._template.SetState(instruction)
self.BindPassFailKeys(fail_later=_FAIL_LATER)
class CheckLEDTaskChallenge(CheckLEDTask):
"""Checks for LED colors interactively.
Args:
color_options: The color options for the operator to choose.
"""
def __init__(self, ui, template, led, nth, color, color_label,
index, index_label, color_options):
super(CheckLEDTaskChallenge, self).__init__(
ui, template, led, nth, color, color_label, index, index_label)
self._color_options = color_options
def _InitUI(self):
desc = i18n_test_ui.MakeI18nLabel(
'<span class="sub-title">Test {test_id}</span><br>'
'Please press number key according to the <strong>{name}</strong> '
'color',
test_id=self._nth, name=self._index_label)
btn_ui = ''.join([
_HTML_KEY_TEMPLATE % (_COLOR_CODE[c] + (_SELECT_COLOR_EVENT, j, j + 1))
for j, c in enumerate(self._color_options)])
ui = [desc, '<br><br>', btn_ui, _HTML_RESULT]
def _Judge(event):
if event.data == target:
self._ui.CallJSFunction('UpdateResult', True)
time.sleep(_SHOW_RESULT_SECONDS)
self.Pass()
else:
self._ui.CallJSFunction('UpdateResult', False)
time.sleep(_SHOW_RESULT_SECONDS)
self.Fail('LED color incorrect or wrong button pressed')
target = self._color_options.index(self._color)
self._ui.AddEventHandler(_SELECT_COLOR_EVENT, _Judge)
for i, _ in enumerate(self._color_options):
self._ui.BindKey(str(i + 1), _Judge, i, virtual_key=False)
self._ui.AppendCSS(_CSS)
self._template.SetState(''.join(ui))
self._ui.RunJS(_JS_OP_RESPONSE)
class FixtureCheckLEDTask(factory_task.FactoryTask):
"""A FactoryTask that uses fixture to check LED color.
Args:
fixture: BFTFixture instance.
led: dut.led.LED instance to control LED.
color: LEDColor to inspect.
color_label: Label for inspected color.
index: Target LED to inspect (unused yet).
index_label: Label for inspected index (unused yet).
"""
def __init__(self, fixture, led, color, color_label, index, index_label):
super(FixtureCheckLEDTask, self).__init__()
self._fixture = fixture
self._led = led
self._color = color
self._color_label = color_label
self._index = index
self._index_label = index_label
def Run(self):
"""Lights LED in color and asks fixture to verify it."""
self._led.SetColor(self._color)
self._CheckFixture()
def _CheckFixture(self):
"""Asks fixture to check if LED lights self._color.
It passes the task if fixture replies with the expected value.
"""
try:
if self._fixture.IsLEDColor(self._color):
self.Pass()
else:
# Fail later to detect all colors.
self.Fail('Unable to detect %s LED.' % self._color_label['en-US'],
later=_FAIL_LATER)
except bft_fixture.BFTFixtureException:
logging.exception('Failed to send command to BFT fixture')
self.Fail('Failed to send command to BFT fixture.')
def Cleanup(self):
"""Turns the light off after the test."""
if self._index is None:
self._led.SetColor(LEDColor.OFF)
else:
self._led.SetColor(LEDColor.OFF, led_name=self._index)
class LEDTest(unittest.TestCase):
"""Tests if the onboard LED can light up with specified colors."""
ARGS = [
Arg('bft_fixture', dict, bft_fixture.TEST_ARG_HELP, optional=True),
Arg('challenge', bool, 'Show random LED sequence and let the operator '
'select LED number instead of pre-defined sequence.', default=False),
Arg('colors', (list, tuple),
'List of colors or (index, color) to test. color must be in '
'LEDColor or OFF, and index, if specified, must be in LEDIndex.',
default=[LEDColor.YELLOW, LEDColor.GREEN, LEDColor.RED,
LEDColor.OFF]),
Arg('target_leds', (list, tuple),
'List of LEDs to test. If specified, it turns off all LEDs first, '
'and sets them to auto after test.', optional=True)]
def setUp(self):
self._dut = device_utils.CreateDUTInterface()
self._ui = test_ui.UI()
self._template = ui_templates.OneSection(self._ui)
self._task_manager = None
self._fixture = None
if self.args.bft_fixture:
self._fixture = bft_fixture.CreateBFTFixture(**self.args.bft_fixture)
self._SetAllLED(self.args.target_leds, LEDColor.OFF)
def tearDown(self):
self._SetAllLED(self.args.target_leds, LEDColor.AUTO)
if self._fixture:
self._fixture.Disconnect()
def runTest(self):
self._template.SetTitle(_TEST_TITLE)
tasks = []
colors = self.args.colors
# Shuffle the colors for interactive challenge, so operators can't guess
# the sequence.
if self.args.challenge:
color_options = list(set([x if isinstance(x, str) else x[1]
for x in colors]))
colors = list(colors)
random.shuffle(colors)
for i, index_color in enumerate(colors):
if isinstance(index_color, str):
color = index_color
index = None
else:
index, color = index_color
color_label = _COLOR_LABEL[color]
index_label = self._GetIndexLabel(index)
if self._fixture:
tasks.append(FixtureCheckLEDTask(self._fixture, self._dut.led,
color, color_label,
index, index_label))
elif self.args.challenge:
tasks.append(CheckLEDTaskChallenge(self._ui, self._template,
self._dut.led, i + 1,
color, color_label,
index, index_label,
color_options))
else:
tasks.append(CheckLEDTaskNormal(self._ui, self._template,
self._dut.led, i + 1,
color, color_label,
index, index_label))
self._task_manager = factory_task.FactoryTaskManager(self._ui, tasks)
self._task_manager.Run()
def _GetIndexLabel(self, index):
if index in _INDEX_LABEL:
return _INDEX_LABEL[index]
else:
return _(index)
def _SetAllLED(self, leds, color):
"""Sets all LEDs to a given color.
Args:
leds: List of LED index. None for default LED.
color: One of LEDColor.
"""
if not self._dut.led:
# Sanity check. It should not happen.
return
if not leds:
self._dut.led.SetColor(color)
return
for led in leds:
self._dut.led.SetColor(color, led_name=led)