| # 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. |
| # |
| # This is a test to verify HWID during factory flow. The test supports three |
| # ways of fetching/probing HWID: |
| # 1) Manually select by operator. |
| # 2) Fetch from shop floor server. |
| # 3) Auto probe for best match HWID. |
| # |
| # To use the auto-probing feature, you have to specify some arguments to the |
| # test. Please refer to ARGS below for detailed explanation. |
| |
| import logging |
| import re |
| import unittest |
| |
| import factory_common # pylint: disable=unused-import |
| from cros.factory.device import device_utils |
| from cros.factory.hwid.v2 import hwid_tool |
| from cros.factory.test import factory |
| from cros.factory.test import factory_task |
| from cros.factory.test import gooftools |
| from cros.factory.test.i18n import test_ui as i18n_test_ui |
| from cros.factory.test import shopfloor |
| from cros.factory.test import test_ui |
| from cros.factory.test import ui_templates |
| from cros.factory.utils.arg_utils import Arg |
| from cros.factory.utils import process_utils |
| |
| _MESSAGE_FETCH_FROM_SHOP_FLOOR = i18n_test_ui.MakeI18nLabelWithClass( |
| 'Fetching HWID from shop floor server...', 'hwid-font-size') |
| _MESSAGE_AUTO_PROBE_HWID = i18n_test_ui.MakeI18nLabelWithClass( |
| 'Auto probing HWID...', 'hwid-font-size') |
| _MESSAGE_WRITING = (lambda hwid: i18n_test_ui.MakeI18nLabelWithClass( |
| 'Writing HWID: {hwid}', 'hwid-font-size', hwid=hwid)) |
| _MESSAGE_CHOOSE_HWID = i18n_test_ui.MakeI18nLabelWithClass( |
| 'Select HWID:<br><br>', 'hwid-font-size') |
| _MESSAGE_HOW_TO_SELECT = i18n_test_ui.MakeI18nLabelWithClass( |
| '<br><br>Select with Enter key', 'hwid-font-size') |
| _MESSAGE_CURRENT_VALUE = lambda hwid: '%s (Current Value)' % hwid |
| |
| _TEST_DEFAULT_CSS = '.hwid-font-size {font-size: 2em;}' |
| _SELECT_BOX_STYLE = 'font-size: 1.5em; background-color: white;' |
| |
| _SELECT_BOX_ID = 'hwid_select' |
| _SELECTION_PER_PAGE = 10 |
| _EVENT_SUBTYPE_HWID_SELECT = 'HWID-Select' |
| _JS_HWID_SELECT = """ |
| ele = document.getElementById("%s"); |
| idx = ele.selectedIndex; |
| window.test.sendTestEvent("%s", ele.options[idx].value) |
| """ % (_SELECT_BOX_ID, _EVENT_SUBTYPE_HWID_SELECT) |
| |
| _ERR_HWID_NOT_FOUND = i18n_test_ui.MakeI18nLabelWithClass( |
| 'Cannot find matched HWID.', 'hwid-font-size test-error') |
| |
| _TEST_TITLE = i18n_test_ui.MakeI18nLabel('HWID Test') |
| |
| |
| class WriteHWIDTask(factory_task.FactoryTask): |
| """Writes HWID using gooftool.""" |
| |
| def __init__(self, test): |
| super(WriteHWIDTask, self).__init__() |
| self.test = test |
| |
| def Run(self): |
| hwid = self.test.hwid |
| if not hwid: |
| raise ValueError('Invalid empty HWID') |
| |
| self.test.template.SetState(_MESSAGE_WRITING(hwid)) |
| # TODO(hungte) Support partial matching by gooftools or hwid_tool. |
| # When the input is not a complete HWID (i.e., BOM-VARIANT pair), select |
| # and derive the complete ID from active HWIDs in current database. |
| # Ex: input="BLUE A" => matched to "MARIO BLUE A-B 6868". |
| current_hwid = process_utils.CheckOutput(['crossystem', 'hwid']).strip() |
| # To save time, only do HWID write if the input HWID is different from |
| # the one already on the system. |
| if hwid != current_hwid: |
| gooftools.run("gooftool write_hwid '%s'" % hwid) |
| else: |
| logging.info('Probed HWID is the same as the one already on ' |
| 'the machine. Skip write.') |
| self.Stop() |
| |
| |
| class ShopFloorHWIDTask(factory_task.FactoryTask): |
| """Fetchs HWID from shop floor server.""" |
| |
| def __init__(self, test): |
| super(ShopFloorHWIDTask, self).__init__() |
| self.test = test |
| |
| def Run(self): |
| shopfloor.update_local_hwid_data(self.test.dut) |
| self.test.template.SetState(_MESSAGE_FETCH_FROM_SHOP_FLOOR) |
| self.test.hwid = shopfloor.get_hwid() |
| self.Stop() |
| |
| |
| class AutoProbeHWIDTask(factory_task.FactoryTask): |
| """Automatically probes matched HWID(s) using gooftool.""" |
| |
| def __init__(self, test): |
| super(AutoProbeHWIDTask, self).__init__() |
| self.test = test |
| |
| def Run(self): |
| if shopfloor.is_enabled(): |
| shopfloor.update_local_hwid_data(self.test.dut) |
| self.test.template.SetState(_MESSAGE_AUTO_PROBE_HWID) |
| gooftool_cmd = 'gooftool best_match_hwids' |
| if self.test.args.missing: |
| gooftool_cmd += ' --missing ' + ' '.join(self.test.args.missing) |
| if self.test.args.comps: |
| gooftool_cmd += ' --comps ' + ' '.join(self.test.args.comps) |
| if self.test.args.variant: |
| gooftool_cmd += ' --variant %s' % self.test.args.variant |
| if self.test.args.status: |
| gooftool_cmd += ' --status %s' % self.test.args.status |
| (stdout, _, _) = gooftools.run(gooftool_cmd) |
| matched_hwids = re.findall(r'^MATCHING HWID: (.+)$', stdout, |
| re.MULTILINE) |
| |
| if matched_hwids: |
| self.test.hwid_list = [] |
| # Use hwid_tool.hwid_tool.HWID_RE to check the format of probed HWIDs |
| for i in xrange(0, len(matched_hwids)): |
| match = hwid_tool.HWID_RE.search(matched_hwids[i]).group(0) |
| if match: |
| self.test.hwid_list.append(match) |
| logging.info('Found matched HWIDs: %s', self.test.hwid_list) |
| else: |
| self.test.template.SetState(_ERR_HWID_NOT_FOUND) |
| factory.console.error('Cannot find matched HWID.') |
| self.Stop() |
| |
| |
| class SelectHWIDTask(factory_task.FactoryTask): |
| """Shows a list of HWIDs on UI and let operator choose a HWID from the it.""" |
| |
| def __init__(self, test): |
| super(SelectHWIDTask, self).__init__() |
| self.test = test |
| self.pages = 0 |
| self.page_index = 0 |
| self.hwid_list = None |
| |
| def BuildHWIDList(self): |
| current_hwid = (self.test.hwid or |
| process_utils.CheckOutput(['crossystem', 'hwid']).strip()) |
| |
| if self.test.hwid_list: |
| known_list = self.test.hwid_list |
| else: |
| (stdout, _, result) = gooftools.run('hwid_tool hwid_list', |
| ignore_status=True) |
| known_list = stdout.splitlines() |
| if (not known_list) or (result != 0): |
| factory.console.error('Warning: No valid HWID database in system.') |
| known_list = [] |
| |
| # Build a list with elements in (hwid_value, display_text). |
| # The first element is "current value". |
| hwids = [(current_hwid, _MESSAGE_CURRENT_VALUE(current_hwid))] |
| hwids += [(hwid, hwid) for hwid in known_list] |
| return hwids |
| |
| def SetHWID(self, event): |
| # TODO(tammo) Use hwid_tool or probe to quick probe if selected HWID |
| # matches current system, by checking non-firmware components. |
| self.test.hwid = event.data |
| self.Stop() |
| |
| def RenderPage(self): |
| self.test.template.SetState(_MESSAGE_CHOOSE_HWID) |
| select_list = ui_templates.SelectBox(_SELECT_BOX_ID, _SELECTION_PER_PAGE, |
| _SELECT_BOX_STYLE) |
| for data in self.hwid_list: |
| select_list.InsertOption(data[0], data[1]) |
| select_list.SetSelectedIndex(0) |
| self.test.template.SetState(select_list.GenerateHTML(), append=True) |
| self.test.template.SetState(_MESSAGE_HOW_TO_SELECT, append=True) |
| self.test.ui.BindKeyJS(test_ui.ENTER_KEY, _JS_HWID_SELECT) |
| self.test.ui.AddEventHandler(_EVENT_SUBTYPE_HWID_SELECT, self.SetHWID) |
| self.test.ui.SetFocus(_SELECT_BOX_ID) |
| |
| def Run(self): |
| self.hwid_list = self.BuildHWIDList() |
| |
| # Skip if auto_select is True and there is only one match. |
| # hwid_list[0] is the current system HWID and hwid_list[1] is the |
| # probed one. |
| if len(self.hwid_list) == 2 and self.test.args.auto_select: |
| self.test.hwid = self.hwid_list[1][1] |
| self.Stop() |
| |
| self.RenderPage() |
| |
| |
| class HWIDTest(unittest.TestCase): |
| ARGS = [ |
| Arg('override_hwid', (str, unicode), |
| 'An override HWID which is used during development.', default=None, |
| optional=True), |
| Arg('manual_override', bool, |
| 'Whether to allow manual HWID selection even ' |
| 'when the shopfloor server is enabled.', default=False, |
| optional=True), |
| Arg('auto_probe', bool, 'Whether to enable HWID auto probe.', |
| default=False, optional=True), |
| Arg('auto_select', bool, |
| 'Whether to auto select HWID if there is only one match', |
| default=True, optional=True), |
| Arg('missing', list, |
| 'A list of missing components in the following format:' |
| '["comp1", "comp2", ..]', default=None, optional=True), |
| Arg('comps', list, |
| 'A list of known component canonicals to pass to gooftool in the' |
| 'following format: ["comp_canonical1", "comp_canonical2", ...]', |
| default=None, optional=True), |
| Arg('variant', (str, unicode), |
| 'A string indicating the variant code to pass to gooftool', |
| default=None, optional=True), |
| Arg('status', (str, unicode), |
| 'A string indicating from what status of HWIDs should the program' |
| 'find possible match. (deprecated, eol, qualified, supported)', |
| default='supported', optional=True)] |
| |
| def setUp(self): |
| self.hwid = None |
| self.hwid_list = None |
| self.task_list = [] |
| self.dut = device_utils.CreateDUTInterface() |
| self.ui = test_ui.UI() |
| self.template = ui_templates.OneSection(self.ui) |
| self.ui.AppendCSS(_TEST_DEFAULT_CSS) |
| self.template.SetTitle(_TEST_TITLE) |
| |
| def runTest(self): |
| self.hwid = self.args.override_hwid |
| |
| if not self.args.override_hwid: |
| if self.args.auto_probe: |
| self.task_list.append(AutoProbeHWIDTask(self)) |
| self.task_list.append(SelectHWIDTask(self)) |
| else: |
| if shopfloor.is_enabled(): |
| device_data = shopfloor.GetDeviceData() |
| if 'hwid' in device_data: |
| self.hwid = device_data['hwid'] |
| else: |
| self.task_list.append(ShopFloorHWIDTask(self)) |
| if not shopfloor.is_enabled() or self.args.manual_override: |
| self.task_list.append(SelectHWIDTask(self)) |
| self.task_list.append(WriteHWIDTask(self)) |
| |
| factory_task.FactoryTaskManager(self.ui, self.task_list).Run() |