blob: 2d89ec9da42e8e4cccc21593676446009a683394 [file] [log] [blame]
#!/bin/env python
#
# 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.
"""Unit tests for HWID v3 utility functions."""
import copy
import logging
import mock
import os
import tempfile
import unittest
import yaml
import factory_common # pylint: disable=W0611
from cros.factory.hwid.v2 import hwid_tool
from cros.factory.hwid.v3 import common
from cros.factory.hwid.v3 import database
from cros.factory.hwid.v3 import hwid_utils
from cros.factory.hwid.v3 import rule
from cros.factory.hwid.v3.rule import Value
from cros.factory.test.rules import phase
from cros.factory.utils import sys_utils
from cros.factory.utils import yaml_utils
TEST_DATA_PATH = os.path.join(os.path.dirname(__file__), 'testdata')
class HWIDv3UtilsTestWithNewDatabase(unittest.TestCase):
"""Test cases for HWID v3 utilities with the new database.
The new database adds a new image_id and a pattern, that removes display_panel
and cellular field, and add firmware_keys field. It also adds SKU that has no
audio_codec component.
"""
def setUp(self):
self.db = database.Database.LoadFile(
os.path.join(TEST_DATA_PATH, 'NEW_TEST_BOARD'))
self.probed_results = list(yaml.load_all(open(os.path.join(
TEST_DATA_PATH, 'new_test_probe_result_hwid_utils.yaml')).read()))
self.vpd = {
'ro': {
'region': 'us',
'serial_number': 'foo'
},
'rw': {
'gbind_attribute': '333333333333333333333333333333333333'
'33333333333333333333333333332dbecc73',
'ubind_attribute': '323232323232323232323232323232323232'
'323232323232323232323232323256850612'
}
}
def testGenerateHWID(self):
device_info = {
'component.keyboard': 'us',
}
# Test new database with audio codec
self.assertEquals(
'CHROMEBOOK E35-A2Y-A7B',
hwid_utils.GenerateHWID(
self.db, self.probed_results[0],
device_info, self.vpd, False).encoded_string)
# Test new database without audio codec
self.assertEquals(
'CHROMEBOOK E45-A2Y-A2Z',
hwid_utils.GenerateHWID(
self.db, self.probed_results[1],
device_info, self.vpd, False).encoded_string)
def testDecodeHWID(self):
"""Tests HWID decoding."""
# Decode old HWID string
hwid = hwid_utils.DecodeHWID(self.db, 'CHROMEBOOK D9I-F9U')
parsed_result = hwid_utils.ParseDecodedHWID(hwid)
self.assertNotIn('firmware_keys', parsed_result)
self.assertEquals(parsed_result['components']['cellular'], [{None: None}])
self.assertEquals(parsed_result['components']['audio_codec'],
[{'codec_1': {'compact_str': Value('Codec 1')}},
{'hdmi_1': {'compact_str': Value('HDMI 1')}}])
self.assertEquals(parsed_result['components']['display_panel'],
[{'display_panel_0': None}])
# Decode new HWID string with audio_codec
hwid = hwid_utils.DecodeHWID(self.db, 'CHROMEBOOK E35-A2Y-A7B')
parsed_result = hwid_utils.ParseDecodedHWID(hwid)
self.assertNotIn('display_panel', parsed_result)
self.assertNotIn('cellular', parsed_result)
self.assertEquals(parsed_result['components']['firmware_keys'],
[{'firmware_keys_mp': {
'key_recovery': Value('kv3#key_recovery_mp'),
'key_root': Value('kv3#key_root_mp')}}])
self.assertEquals(parsed_result['components']['audio_codec'],
[{'codec_1': {'compact_str': Value('Codec 1')}},
{'hdmi_1': {'compact_str': Value('HDMI 1')}}])
# Decode new HWID string without audio_codec
hwid = hwid_utils.DecodeHWID(self.db, 'CHROMEBOOK E45-A2Y-A2Z')
parsed_result = hwid_utils.ParseDecodedHWID(hwid)
self.assertNotIn('display_panel', parsed_result)
self.assertNotIn('cellular', parsed_result)
self.assertEquals(parsed_result['components']['firmware_keys'],
[{'firmware_keys_mp': {
'key_recovery': Value('kv3#key_recovery_mp'),
'key_root': Value('kv3#key_root_mp')}}])
self.assertEquals(parsed_result['components']['audio_codec'],
[{None: None}])
class HWIDv3UtilsTest(unittest.TestCase):
"""Test cases for HWID v3 utilities."""
def setUp(self):
self.db = database.Database.LoadFile(
os.path.join(TEST_DATA_PATH, 'TEST_BOARD'))
self.probed_results = yaml.load(open(os.path.join(
TEST_DATA_PATH, 'test_probe_result_hwid_utils.yaml')).read())
self.vpd = {
'ro': {
'region': 'us',
'serial_number': 'foo'
},
'rw': {
'gbind_attribute': '333333333333333333333333333333333333'
'33333333333333333333333333332dbecc73',
'ubind_attribute': '323232323232323232323232323232323232'
'323232323232323232323232323256850612'
}
}
def testVerifyComponentsV3(self):
"""Test if the Gooftool.VerifyComponent() works properly.
This test tries to probe four components [bluetooth, battery, cpu,
audio_codec], where
'bluetooth' returns a valid result.
'battery' returns a false result.
'cpu' does not return any result.
'audio_codec' returns multiple results.
"""
probed_results = yaml.load(hwid_tool.ProbeResults(
found_probe_value_map={
'bluetooth': {
'idVendor': '0123',
'idProduct': 'abcd',
'bcd': '0001'},
'battery': {
'compact_str': 'fake value'},
'audio_codec': [
{'compact_str': 'Codec 1'},
{'compact_str': 'HDMI 1'},
{'compact_str': 'fake value'}]},
missing_component_classes=[],
found_volatile_values={},
initial_configs={}).Encode())
results = hwid_utils.VerifyComponents(
self.db, probed_results,
['bluetooth', 'battery', 'cpu', 'audio_codec'])
self.assertEquals(
[('bluetooth_0',
{'idVendor': rule.Value('0123'), 'idProduct': rule.Value('abcd'),
'bcd': rule.Value('0001')},
None)],
results['bluetooth'])
self.assertEquals(
[(None, None, "Missing 'cpu' component")],
results['cpu'])
self.assertEquals(
[(None, {'compact_str': 'fake value'},
("Invalid 'battery' component found with probe result "
"{ 'compact_str': 'fake value'} "
'(no matching name in the component DB)'))],
results['battery'])
self.assertEquals(
[('codec_1', {'compact_str': rule.Value('Codec 1')}, None),
('hdmi_1', {'compact_str': rule.Value('HDMI 1')}, None),
(None, {'compact_str': 'fake value'},
("Invalid 'audio_codec' component found with probe result "
"{ 'compact_str': 'fake value'} "
'(no matching name in the component DB)'))],
results['audio_codec'])
def testVerifyBadComponents3(self):
"""Tests VerifyComponents with invalid component class name."""
probed_results = yaml.load(hwid_tool.ProbeResults(
found_probe_value_map={},
missing_component_classes=[],
found_volatile_values={},
initial_configs={}).Encode())
self.assertRaises(common.HWIDException, hwid_utils.VerifyComponents,
self.db, probed_results, ['cpu', 'bad_class_name'])
def testGenerateHWID(self):
"""Tests HWID generation."""
device_info = {
'component.has_cellular': False,
'component.keyboard': 'us',
'component.dram': 'foo',
'component.audio_codec': 'set_1'
}
self.assertEquals(
'CHROMEBOOK D9I-E4A-A2B',
hwid_utils.GenerateHWID(
self.db, self.probed_results,
device_info, self.vpd, False).encoded_string)
device_info = {
'component.has_cellular': True,
'component.keyboard': 'gb',
'component.dram': 'foo',
'component.audio_codec': 'set_1'
}
self.assertEquals(
'CHROMEBOOK D92-E4A-A87',
hwid_utils.GenerateHWID(
self.db, self.probed_results,
device_info, self.vpd, False).encoded_string)
device_info = {
'component.has_cellular': True,
'component.keyboard': 'gb',
'component.dram': 'foo',
'component.audio_codec': 'set_0'
}
self.assertEquals(
'CHROMEBOOK D52-E4A-A7E',
hwid_utils.GenerateHWID(
self.db, self.probed_results,
device_info, self.vpd, False).encoded_string)
def testVerifyHWID(self):
"""Tests HWID verification."""
self.assertEquals(None, hwid_utils.VerifyHWID(
self.db, 'CHROMEBOOK A5AU-LU', self.probed_results, self.vpd, False,
phase.EVT))
for current_phase in (phase.PVT, phase.PVT_DOGFOOD):
self.assertEquals(None, hwid_utils.VerifyHWID(
self.db, 'CHROMEBOOK D9I-F9U', self.probed_results, self.vpd, False,
current_phase))
# Check for mismatched phase.
self.assertRaisesRegexp(
common.HWIDException,
r"In DVT phase, expected an image name beginning with 'DVT' "
r"\(but .* has image ID 'PVT2'\)",
hwid_utils.VerifyHWID,
self.db, 'CHROMEBOOK D9I-F9U', self.probed_results, self.vpd, False,
phase.DVT)
# Check for missing RO VPD.
vpd = copy.deepcopy(self.vpd)
del vpd['ro']['serial_number']
self.assertRaisesRegexp(
rule.RuleException, r"KeyError\('serial_number',\)",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F9U',
self.probed_results, vpd, False, phase.PVT)
# Check for invalid RO VPD.
vpd = copy.deepcopy(self.vpd)
vpd['ro']['region'] = 'invalid_region'
self.assertRaisesRegexp(
rule.RuleException,
r"Invalid VPD value 'invalid_region' of 'region'",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F9U',
self.probed_results, vpd, False, phase.PVT)
# Check for missing RW VPD.
vpd = copy.deepcopy(self.vpd)
del vpd['rw']['gbind_attribute']
self.assertRaisesRegexp(
rule.RuleException, r"KeyError\('gbind_attribute',\)",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F9U',
self.probed_results, vpd, False, phase.PVT)
# Check for invalid RW VPD.
vpd = copy.deepcopy(self.vpd)
vpd['rw']['gbind_attribute'] = 'invalid_gbind_attribute'
self.assertRaisesRegexp(
rule.RuleException,
r"Invalid registration code 'invalid_gbind_attribute'",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F9U',
self.probed_results, vpd, False, phase.PVT)
probed_results = copy.deepcopy(self.probed_results)
probed_results['found_probe_value_map']['audio_codec'][1] = {
'compact_str': 'HDMI 2'}
self.assertRaisesRegexp(
common.HWIDException,
(r"Component class 'audio_codec' is missing components: "
r"\['hdmi_1'\]. Expected components are: \['codec_1', 'hdmi_1'\]"),
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F9U', probed_results,
self.vpd, False, phase.PVT)
# Test pre-MP recovery/root keys.
probed_results = copy.deepcopy(self.probed_results)
probed_results['found_volatile_values']['key_root'].update(
{'compact_str': 'kv3#key_root_premp'})
probed_results['found_volatile_values']['key_recovery'].update(
{'compact_str': 'kv3#key_recovery_premp'})
# Pre-MP recovery/root keys are fine in DVT...
self.assertEquals(None, hwid_utils.VerifyHWID(
self.db, 'CHROMEBOOK B5AW-5W', probed_results, self.vpd, False,
phase.DVT))
# ...but not in PVT
self.assertRaisesRegexp(
common.HWIDException,
'MP keys are required in PVT, but key_recovery component name is '
"'key_recovery_premp' and key_root component name is 'key_root_premp'",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-F6A-A6B',
probed_results, self.vpd, False, phase.PVT)
# Test deprecated component.
probed_results = copy.deepcopy(self.probed_results)
probed_results['found_volatile_values']['ro_main_firmware'].update(
{'compact_str': 'mv2#ro_main_firmware_1'})
self.assertRaisesRegexp(
common.HWIDException, r'Not in RMA mode. Found deprecated component of '
r"'ro_main_firmware': 'ro_main_firmware_1'",
hwid_utils.VerifyHWID, self.db, 'CHROMEBOOK D9I-H9T', probed_results,
self.vpd, False, phase.PVT)
# Test deprecated component is allowed in rma mode.
self.assertEquals(None, hwid_utils.VerifyHWID(
self.db, 'CHROMEBOOK D9I-H9T', probed_results, self.vpd, True,
phase.PVT))
# Test unqualified component.
probed_results = copy.deepcopy(self.probed_results)
probed_results['found_probe_value_map']['dram'].update(
{'vendor': 'DRAM 2',
'size': '8G'})
self.assertRaisesRegexp(
common.HWIDException, r'Found unqualified component of '
r"'dram': 'dram_2' in Phase\(PVT\)",
hwid_utils.VerifyHWID, self.db,
'CHROMEBOOK D9I-E8A-A5F', probed_results,
self.vpd, False, phase.PVT)
# Test unqualified component is allowed in early builds: PROTO/EVT/DVT.
self.assertEquals(None, hwid_utils.VerifyHWID(
self.db, 'CHROMEBOOK A5AT-PC', probed_results, self.vpd, False,
phase.EVT))
def testDecodeHWID(self):
"""Tests HWID decoding."""
hwid = hwid_utils.DecodeHWID(self.db, 'CHROMEBOOK D9I-F9U')
self.assertEquals(
{'audio_codec': 1, 'battery': 3, 'firmware': 0, 'storage': 0,
'bluetooth': 0, 'video': 0, 'display_panel': 0, 'cellular': 0,
'keyboard': 0, 'dram': 0, 'cpu': 5},
hwid.bom.encoded_fields)
parsed_result = hwid_utils.ParseDecodedHWID(hwid)
self.assertEquals(parsed_result['board'], 'CHROMEBOOK')
self.assertEquals(parsed_result['binary_string'], '000111110100000101')
self.assertEquals(parsed_result['image_id'], 'PVT2')
self.assertEquals(parsed_result['components'], {
'key_recovery': [{
'key_recovery_mp': {
'compact_str': Value('kv3#key_recovery_mp', is_re=False)}}],
'cellular': [{None: None}],
'ro_main_firmware': [{
'ro_main_firmware_0': {
'compact_str': Value('mv2#ro_main_firmware_0', is_re=False)}}],
'battery': [{
'battery_huge': {
'tech': Value('Battery Li-ion', is_re=False),
'size': Value('10000000', is_re=False)}}],
'hash_gbb': [{
'hash_gbb_0': {
'compact_str': Value('gv2#hash_gbb_0', is_re=False)}}],
'bluetooth': [{
'bluetooth_0': {
'bcd': Value('0001', is_re=False),
'idVendor': Value('0123', is_re=False),
'idProduct': Value('abcd', is_re=False)}}],
'key_root': [{
'key_root_mp': {
'compact_str': Value('kv3#key_root_mp', is_re=False)}}],
'video': [{
'camera_0': {
'idVendor': Value('4567', is_re=False),
'type': Value('webcam', is_re=False),
'idProduct': Value('abcd', is_re=False)}}],
'audio_codec': [
{'codec_1': {'compact_str': Value('Codec 1', is_re=False)}},
{'hdmi_1': {'compact_str': Value('HDMI 1', is_re=False)}}],
'keyboard': [{'keyboard_us': None}],
'dram': [{
'dram_0': {
'vendor': Value('DRAM 0', is_re=False),
'size': Value('4G', is_re=False)}}],
'storage': [{
'storage_0': {
'serial': Value('#123456', is_re=False),
'type': Value('SSD', is_re=False),
'size': Value('16G', is_re=False)}}],
'display_panel': [{'display_panel_0': None}],
'ro_ec_firmware':[{
'ro_ec_firmware_0': {
'compact_str': Value('ev2#ro_ec_firmware_0', is_re=False)}}],
'cpu': [{
'cpu_5': {
'cores': Value('4', is_re=False),
'name': Value('CPU @ 2.80GHz', is_re=False)}}]})
class DatabaseBuilderTest(unittest.TestCase):
def setUp(self):
yaml_utils.ParseMappingAsOrderedDict()
with open(os.path.join(TEST_DATA_PATH,
'test_builder_probe_results.yaml'), 'r') as f:
self.probed_results = list(yaml.load_all(f.read()))
self.output_path = tempfile.mktemp()
def tearDown(self):
yaml_utils.ParseMappingAsOrderedDict(False)
if os.path.exists(self.output_path):
os.remove(self.output_path)
def testBuildDatabase(self):
# Build database by the probed result.
hwid_utils.BuildDatabase(
self.output_path, self.probed_results[0], 'CHROMEBOOK', 'EVT',
add_comp=['dram'], del_comp=None,
region=['tw', 'jp'], customization_id=['FOO', 'BAR'])
# If not in Chroot, the checksum is not updated.
verify_checksum = sys_utils.InChroot()
database.Database.LoadFile(self.output_path, verify_checksum)
# Check the value.
with open(self.output_path, 'r') as f:
db = yaml.load(f.read())
self.assertEquals(db['board'], 'CHROMEBOOK')
self.assertEquals(db['image_id'], {0: 'EVT'})
self.assertEquals(db['pattern'][0]['image_ids'], [0])
self.assertEquals(db['pattern'][0]['encoding_scheme'], 'base8192')
active_fields = [{'region_field': 8},
{'customization_id_field': 5},
{'ro_main_firmware_field': 3},
{'firmware_keys_field': 3},
{'ro_pd_firmware_field': 3},
{'ro_ec_firmware_field': 3},
{'storage_field': 1},
{'cpu_field': 1},
{'dram_field': 1},
{'wireless_field': 0},
{'display_panel_field': 0},
{'tpm_field': 0},
{'flash_chip_field': 0},
{'audio_codec_field': 0},
{'usb_hosts_field': 0},
{'bluetooth_field': 0}]
for field in active_fields:
self.assertIn(field, db['pattern'][0]['fields'])
self.assertEquals(set(db['components'].keys()),
set(['dram', 'ro_pd_firmware', 'ro_main_firmware', 'tpm',
'storage', 'flash_chip', 'bluetooth', 'wireless',
'display_panel', 'audio_codec', 'firmware_keys',
'ro_ec_firmware', 'usb_hosts', 'cpu', 'region',
'customization_id']))
self.assertEquals(db['rules'],
[{'name': 'device_info.image_id',
'evaluate': "SetImageId('EVT')"}])
# Add a component without a new image_id.
probed_result = self.probed_results[0].copy()
probed_result['found_probe_value_map']['touchpad'] = {'name': 'G_touchpad'}
new_db = copy.deepcopy(db)
with mock.patch('__builtin__.raw_input', return_value='n'):
with self.assertRaises(ValueError):
hwid_utils.UpdateDatabase(self.output_path, probed_result, new_db)
new_db = copy.deepcopy(db)
with mock.patch('__builtin__.raw_input', return_value='y'):
hwid_utils.UpdateDatabase(self.output_path, probed_result, new_db)
self.assertIn({'touchpad_field': 0}, new_db['pattern'][0]['fields'])
# Delete bluetooth, and add region and customization_id.
new_db = copy.deepcopy(db)
hwid_utils.UpdateDatabase(
self.output_path, None, new_db, 'DVT',
add_comp=None, del_comp=['bluetooth'],
region=['us'], customization_id=['NEW'])
database.Database.LoadFile(self.output_path, verify_checksum)
# Check the value.
self.assertEquals(new_db['board'], 'CHROMEBOOK')
self.assertEquals(new_db['image_id'], {0: 'EVT', 1: 'DVT'})
active_fields = [{'region_field': 8},
{'customization_id_field': 5},
{'ro_main_firmware_field': 3},
{'firmware_keys_field': 3},
{'ro_pd_firmware_field': 3},
{'ro_ec_firmware_field': 3},
{'storage_field': 1},
{'cpu_field': 1},
{'dram_field': 1},
{'wireless_field': 0},
{'display_panel_field': 0},
{'tpm_field': 0},
{'flash_chip_field': 0},
{'audio_codec_field': 0},
{'usb_hosts_field': 0}]
for field in active_fields:
self.assertIn(field, new_db['pattern'][1]['fields'])
self.assertNotIn({'bluetooth_field': 0}, new_db['pattern'][1]['fields'])
self.assertIn({'region': 'us'},
new_db['encoded_fields']['region_field'].values())
self.assertIn('NEW', new_db['components']['customization_id']['items'])
self.assertIn({'customization_id': 'NEW'},
new_db['encoded_fields']['customization_id_field'].values())
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
unittest.main()