blob: e4034e8de0811d5c186b18e5eab068b4e916105d [file] [log] [blame]
# Copyright 2018 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.
"""A test to update SKU ID to EEPROM.
Description
-----------
A test to set SKU ID from device data ``component.sku`` to EEPROM by using
``ectool cbi``. If you want to run the pytest `model_sku` with the SKU ID set
by this pytest, you need to reboot the DUT first.
Test Procedure
--------------
This is an automatic test that doesn't need any user interaction.
Dependency
----------
- ``ectool`` utility.
Examples
--------
To set SKU ID from device data to EEPROM, add this in test list::
{
"pytest_name": "update_sku"
}
To set SKU ID and run the pytest `model_sku`, add this in test list::
{
"subtests": [
{
"pytest_name": "update_sku"
},
"FullRebootStep",
{
"pytest_name": "model_sku"
}
]
}
"""
import logging
import re
import subprocess
import factory_common # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.test import device_data
from cros.factory.test import session
from cros.factory.test import test_case
_KEY_COMPONENT_SKU = device_data.JoinKeys(device_data.KEY_COMPONENT, 'sku')
class UpdateSKUIDTest(test_case.TestCase):
"""A test to set SKU ID from device data to EEPROM."""
def setUp(self):
self._dut = device_utils.CreateDUTInterface()
def SetToEEPROM(self):
OEM_ID_TYPE = 1
SKU_ID_TYPE = 2
def GetDataFromEEPROM(data_type):
# Usage: ectool cbi get <type> [get_flag]
# <type> is one of 0: BOARD_VERSION, 1: OEM_ID, 2: SKU_ID
cbi_output = self._dut.CallOutput(
['ectool', 'cbi', 'get', str(data_type)])
# The output from ectool cbi get is 'As integer: %u (0x%x)\n' % (val, val)
match = re.search(r'As integer: ([0-9]+) \(0x[0-9a-fA-F]+\)', cbi_output)
if match:
return int(match.group(1))
else:
self.FailTask('Is the format of the output from "ectool cbi get" '
'changed?')
def GetSKUIDFromDeviceData():
device_data_sku = device_data.GetDeviceData(_KEY_COMPONENT_SKU)
if device_data_sku is None:
self.FailTask('No SKU ID in device data (%s)' % _KEY_COMPONENT_SKU)
elif isinstance(device_data_sku, int):
return device_data_sku
elif isinstance(device_data_sku, basestring):
# This can covert both 10-based and 16-based starting with '0x'.
return int(device_data_sku, 0)
else:
self.FailTask('The SKU ID in device-data is not an integer nor a '
'string representing an integer literal in radix base.')
def GetOEMIDFromCrosConfig(sku_id):
output = self._dut.CallOutput(
['cros_config', '--test_sku_id=%d' % sku_id, '/', 'oem-id']).strip()
if not output:
self.FailTask('Can\'t get OEM ID from cros_config')
return int(output)
new_sku_id = GetSKUIDFromDeviceData()
old_sku_id = GetDataFromEEPROM(SKU_ID_TYPE)
if old_sku_id == new_sku_id:
return
if new_sku_id > 2 ** 32 - 1:
self.FailTask('SKU ID (%d) should not be greater than UINT32_MAX (%d)' %
(new_sku_id, 2 ** 32 - 1))
# The data size should be 1, 2 or 4. See
# https://chromium.googlesource.com/chromiumos/platform/ec/+/master/util/cbi-util.c#140
if new_sku_id <= 2 ** 8 - 1:
data_size = 1
elif new_sku_id <= 2 ** 16 - 1:
data_size = 2
else:
data_size = 4
oem_id_in_eeprom = GetDataFromEEPROM(OEM_ID_TYPE)
oem_id_in_cros_config = GetOEMIDFromCrosConfig(new_sku_id)
if oem_id_in_eeprom != oem_id_in_cros_config:
self.FailTask('OEM ID in EEPROM (%d) is not equal to the OEM ID in '
'cros_config (%d)' % (oem_id_in_eeprom,
oem_id_in_cros_config))
logging.info('Set the new SKU_ID to EEPROM (%d -> %d)',
old_sku_id, new_sku_id)
# Usage: ectool cbi set <type> <value> <size> [set_flag]
# <type> is one of 0: BOARD_VERSION, 1: OEM_ID, 2: SKU_ID
# <value> is integer to be set. No raw data support yet.
# <size> is the size of the data.
command = ['ectool', 'cbi', 'set', str(SKU_ID_TYPE), str(new_sku_id),
str(data_size)]
process = self._dut.Popen(
command=command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
session.console.info('%s: stdout: %s\n', command, stdout)
if process.returncode != 0:
session.console.error('returncode: %d, stderr: %s',
process.returncode, stderr)
self.FailTask('Failed to set SKU ID to EEPROM. returncode=%d, stdout=%s, '
'stderr=%s' % (process.returncode, stdout, stderr))
check_sku_id = GetDataFromEEPROM(SKU_ID_TYPE)
if check_sku_id != new_sku_id:
self.FailTask('The SKU ID in EEPROM (%d) is not equal to the SKU ID in '
'device data (%d) after we set' %
(check_sku_id, new_sku_id))
def runTest(self):
self.SetToEEPROM()