blob: df5982779b7d856666187854bb7b0acd3413dd77 [file] [log] [blame]
#!/usr/bin/env python2
# Copyright 2017 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.
"""The unit test suite for the libcros_config_host.py library"""
from __future__ import print_function
from collections import OrderedDict
from contextlib import contextmanager
from io import BytesIO
import os
import sys
import unittest
import fdt_util
from libcros_config_host import CrosConfig, FORMAT_FDT
from libcros_config_host_base import BaseFile, TouchFile, FirmwareInfo
DTS_FILE = '../libcros_config/test.dts'
YAML_FILE = '../libcros_config/test.yaml'
MODELS = sorted(['some', 'another', 'whitelabel'])
ANOTHER_BUCKET = ('gs://chromeos-binaries/HOME/bcs-another-private/overlay-'
'another-private/chromeos-base/chromeos-firmware-another/')
SOME_BUCKET = ('gs://chromeos-binaries/HOME/bcs-some-private/'
'overlay-some-private/chromeos-base/chromeos-firmware-some/')
SOME_FIRMWARE_FILES = ['Some_EC.1111.11.1.tbz2',
'Some.1111.11.1.tbz2',
'Some_RW.1111.11.1.tbz2']
ANOTHER_FIRMWARE_FILES = ['Another_EC.1111.11.1.tbz2',
'Another.1111.11.1.tbz2',
'Another_RW.1111.11.1.tbz2']
LIB_FIRMWARE = '/lib/firmware/'
TOUCH_FIRMWARE = '/opt/google/touch/firmware/'
# Use this to suppress stdout/stderr output:
# with capture_sys_output() as (stdout, stderr)
# ...do something...
@contextmanager
def capture_sys_output():
capture_out, capture_err = BytesIO(), BytesIO()
old_out, old_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = capture_out, capture_err
yield capture_out, capture_err
finally:
sys.stdout, sys.stderr = old_out, old_err
class CommonTests(object):
"""Shared tests between the YAML and FDT implementations."""
def testGetProperty(self):
config = CrosConfig(self.filepath)
another = config.GetConfig('another')
self.assertEqual(another.GetProperty('/', 'wallpaper'), 'default')
self.assertFalse(another.GetProperty('/', 'missing'))
def testModels(self):
config = CrosConfig(self.filepath)
models = config.GetModelList()
for model in MODELS:
self.assertIn(model, models)
def testGetFirmwareUris(self):
config = CrosConfig(self.filepath)
firmware_uris = config.GetConfig('another').GetFirmwareUris()
self.assertSequenceEqual(
firmware_uris,
sorted([ANOTHER_BUCKET + fname for fname in ANOTHER_FIRMWARE_FILES]))
def testGetSharedFirmwareUris(self):
config = CrosConfig(self.filepath)
firmware_uris = config.GetFirmwareUris()
expected = sorted(
[ANOTHER_BUCKET + fname for fname in ANOTHER_FIRMWARE_FILES] +
[SOME_BUCKET + fname for fname in SOME_FIRMWARE_FILES])
self.assertSequenceEqual(firmware_uris, expected)
def testGetArcFiles(self):
config = CrosConfig(self.filepath)
arc_files = config.GetArcFiles()
self.assertEqual(
arc_files,
[BaseFile(
source='some/hardware_features',
dest='/usr/share/chromeos-config/sbin/some/hardware_features')])
def testGetThermalFiles(self):
config = CrosConfig(self.filepath)
thermal_files = config.GetThermalFiles()
self.assertEqual(
thermal_files,
[BaseFile('another/dptf.dv', '/etc/dptf/another/dptf.dv'),
BaseFile('some_notouch/dptf.dv', '/etc/dptf/some_notouch/dptf.dv'),
BaseFile('some_touch/dptf.dv', '/etc/dptf/some_touch/dptf.dv')])
def testGetFirmwareBuildTargets(self):
config = CrosConfig(self.filepath)
self.assertSequenceEqual(config.GetFirmwareBuildTargets('coreboot'),
['another', 'some'])
os.environ['FW_NAME'] = 'another'
self.assertSequenceEqual(config.GetFirmwareBuildTargets('coreboot'),
['another'])
self.assertSequenceEqual(config.GetFirmwareBuildTargets('ec'),
['another', 'another_base', 'another_cr50'])
del os.environ['FW_NAME']
def testFileTree(self):
"""Test that we can obtain a file tree"""
config = CrosConfig(self.filepath)
node = config.GetFileTree()
self.assertEqual(node.name, '')
self.assertEqual(sorted(node.children.keys()),
['etc', 'lib', 'opt', 'usr'])
etc = node.children['etc']
self.assertEqual(etc.name, 'etc')
cras = etc.children['cras']
self.assertEqual(cras.name, 'cras')
another = cras.children['another']
self.assertEqual(sorted(another.children.keys()),
['a-card', 'dsp.ini'])
def testShowTree(self):
"""Test that we can show a file tree"""
config = CrosConfig(self.filepath)
tree = config.GetFileTree()
with capture_sys_output() as (stdout, stderr):
config.ShowTree('/', tree)
self.assertEqual(stderr.getvalue(), '')
lines = [line.strip() for line in stdout.getvalue().splitlines()]
self.assertEqual(lines[0].split(), ['Size', 'Path'])
self.assertEqual(lines[1], '/')
self.assertEqual(lines[2], 'etc/')
self.assertEqual(lines[3].split(), ['missing', 'cras/'])
def testFimwareBuildCombinations(self):
"""Test generating a dict of firmware build combinations."""
config = CrosConfig(self.filepath)
expected = OrderedDict(
[('another', ['another', 'another']),
('some', ['some', 'some'])])
result = config.GetFirmwareBuildCombinations(['coreboot', 'depthcharge'])
self.assertEqual(result, expected)
os.environ['FW_NAME'] = 'another'
expected = OrderedDict([('another', ['another', 'another'])])
result = config.GetFirmwareBuildCombinations(['coreboot', 'depthcharge'])
self.assertEqual(result, expected)
del os.environ['FW_NAME']
def testGetWallpaper(self):
"""Test that we can access the wallpaper information"""
config = CrosConfig(self.filepath)
wallpaper = config.GetWallpaperFiles()
self.assertEquals(['default',
'some',
'wallpaper-wl1',
'wallpaper-wl2'],
wallpaper)
def testGetTouchFirmwareFiles(self):
def _GetFile(source, symlink):
"""Helper to return a suitable TouchFile"""
return TouchFile(source, TOUCH_FIRMWARE + source,
LIB_FIRMWARE + symlink)
config = CrosConfig(self.filepath)
touch_files = config.GetConfig('another').GetTouchFirmwareFiles()
# pylint: disable=line-too-long
self.assertEqual(
touch_files,
[TouchFile(source='some_stylus_vendor/another-version.hex',
dest='/opt/google/touch/firmware/some_stylus_vendor/another-version.hex',
symlink='/lib/firmware/some_stylus_vendor_firmware_ANOTHER.bin'),
TouchFile(source='some_touch_vendor/some-pid_some-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-pid_some-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-pid.bin')])
touch_files = config.GetConfig('some').GetTouchFirmwareFiles()
# This checks that duplicate processing works correct, since both models
# have the same wacom firmware
self.assertEqual(
touch_files,
[TouchFile(source='some_stylus_vendor/some-version.hex',
dest='/opt/google/touch/firmware/some_stylus_vendor/some-version.hex',
symlink='/lib/firmware/some_stylus_vendor_firmware_SOME.bin'),
TouchFile(source='some_touch_vendor/some-pid_some-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-pid_some-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-pid.bin'),
TouchFile(source='some_touch_vendor/some-other-pid_some-other-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-other-pid_some-other-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-other-pid.bin')])
touch_files = config.GetTouchFirmwareFiles()
expected = set(
[TouchFile(source='some_stylus_vendor/another-version.hex',
dest='/opt/google/touch/firmware/some_stylus_vendor/another-version.hex',
symlink='/lib/firmware/some_stylus_vendor_firmware_ANOTHER.bin'),
TouchFile(source='some_stylus_vendor/some-version.hex',
dest='/opt/google/touch/firmware/some_stylus_vendor/some-version.hex',
symlink='/lib/firmware/some_stylus_vendor_firmware_SOME.bin'),
TouchFile(source='some_touch_vendor/some-pid_some-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-pid_some-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-pid.bin'),
TouchFile(source='some_touch_vendor/some-other-pid_some-other-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-other-pid_some-other-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-other-pid.bin'),
TouchFile(source='some_touch_vendor/some-pid_some-version.bin',
dest='/opt/google/touch/firmware/some_touch_vendor/some-pid_some-version.bin',
symlink='/lib/firmware/some_touch_vendorts_i2c_some-pid.bin')])
self.assertEqual(set(touch_files), expected)
def testGetAudioFiles(self):
config = CrosConfig(self.filepath)
audio_files = config.GetAudioFiles()
expected = \
[BaseFile(source='cras-config/another/dsp.ini',
dest='/etc/cras/another/dsp.ini'),
BaseFile(source='cras-config/another/a-card',
dest='/etc/cras/another/a-card'),
BaseFile(source='cras-config/some/dsp.ini',
dest='/etc/cras/some/dsp.ini'),
BaseFile(source='cras-config/some/a-card',
dest='/etc/cras/some/a-card'),
BaseFile(source='topology/another-tplg.bin',
dest='/lib/firmware/another-tplg.bin'),
BaseFile(source='topology/some-tplg.bin',
dest='/lib/firmware/some-tplg.bin'),
BaseFile(source='ucm-config/a-card.another/HiFi.conf',
dest='/usr/share/alsa/ucm/a-card.another/HiFi.conf'),
BaseFile(source='ucm-config/a-card.another/a-card.another.conf',
dest='/usr/share/alsa/ucm/a-card.another/a-card.another.conf'),
BaseFile(source='ucm-config/a-card.some/HiFi.conf',
dest='/usr/share/alsa/ucm/a-card.some/HiFi.conf'),
BaseFile(source='ucm-config/a-card.some/a-card.some.conf',
dest='/usr/share/alsa/ucm/a-card.some/a-card.some.conf')]
self.assertEqual(audio_files, sorted(expected))
def testFirmware(self):
"""Test access to firmware information"""
config = CrosConfig(self.filepath)
self.assertEqual('updater4.sh', config.GetFirmwareScript())
expected = OrderedDict(
[('another',
FirmwareInfo(model='another',
shared_model=None,
key_id='ANOTHER',
have_image=True,
bios_build_target='another',
ec_build_target='another',
main_image_uri='bcs://Another.1111.11.1.tbz2',
main_rw_image_uri='bcs://Another_RW.1111.11.1.tbz2',
ec_image_uri='bcs://Another_EC.1111.11.1.tbz2',
pd_image_uri='',
extra=['${FILESDIR}/extra'],
create_bios_rw_image=False,
tools=['${FILESDIR}/tools1', '${FILESDIR}/tools2'],
sig_id='another')),
('some',
FirmwareInfo(model='some',
shared_model='some',
key_id='SOME',
have_image=True,
bios_build_target='some',
ec_build_target='some',
main_image_uri='bcs://Some.1111.11.1.tbz2',
main_rw_image_uri='bcs://Some_RW.1111.11.1.tbz2',
ec_image_uri='bcs://Some_EC.1111.11.1.tbz2',
pd_image_uri='',
extra=[],
create_bios_rw_image=False,
tools=[],
sig_id='some')),
('whitelabel',
FirmwareInfo(model='whitelabel',
shared_model='some',
key_id='',
have_image=True,
bios_build_target='some',
ec_build_target='some',
main_image_uri='bcs://Some.1111.11.1.tbz2',
main_rw_image_uri='bcs://Some_RW.1111.11.1.tbz2',
ec_image_uri='bcs://Some_EC.1111.11.1.tbz2',
pd_image_uri='',
extra=[],
create_bios_rw_image=False,
tools=[],
sig_id='sig-id-in-customization-id')),
('whitelabel-whitelabel1',
FirmwareInfo(model='whitelabel-whitelabel1',
shared_model='some',
key_id='WHITELABEL1',
have_image=False,
bios_build_target='some',
ec_build_target='some',
main_image_uri='bcs://Some.1111.11.1.tbz2',
main_rw_image_uri='bcs://Some_RW.1111.11.1.tbz2',
ec_image_uri='bcs://Some_EC.1111.11.1.tbz2',
pd_image_uri='',
extra=[],
create_bios_rw_image=False,
tools=[],
sig_id='whitelabel-whitelabel1')),
('whitelabel-whitelabel2',
FirmwareInfo(model='whitelabel-whitelabel2',
shared_model='some',
key_id='WHITELABEL2',
have_image=False,
bios_build_target='some',
ec_build_target='some',
main_image_uri='bcs://Some.1111.11.1.tbz2',
main_rw_image_uri='bcs://Some_RW.1111.11.1.tbz2',
ec_image_uri='bcs://Some_EC.1111.11.1.tbz2',
pd_image_uri='',
extra=[],
create_bios_rw_image=False,
tools=[],
sig_id='whitelabel-whitelabel2'))])
result = config.GetFirmwareInfo()
self.assertEqual(result, expected)
class CrosConfigHostTestFdt(unittest.TestCase, CommonTests):
"""Tests for master configuration in device tree format"""
def setUp(self):
path = os.path.join(os.path.dirname(__file__), DTS_FILE)
(self.filepath, self.temp_file) = fdt_util.EnsureCompiled(path)
def tearDown(self):
os.remove(self.temp_file.name)
def testGoodDtbFile(self):
self.assertIsNotNone(CrosConfig(self.filepath))
def testNodeSubnames(self):
config = CrosConfig(self.filepath)
for name, model in config.models.iteritems():
self.assertEqual(name, model.name)
def testPathNode(self):
config = CrosConfig(self.filepath)
self.assertIsNotNone(config.models['another'].PathNode('/firmware'))
def testBadPathNode(self):
config = CrosConfig(self.filepath)
self.assertIsNone(config.models['another'].PathNode('/dne'))
def testPathProperty(self):
config = CrosConfig(self.filepath)
another = config.models['another']
ec_image = another.PathProperty('/firmware', 'ec-image')
self.assertEqual(ec_image.value, 'bcs://Another_EC.1111.11.1.tbz2')
def testBadPathProperty(self):
config = CrosConfig(self.filepath)
another = config.models['another']
self.assertIsNone(another.PathProperty('/firmware', 'dne'))
self.assertIsNone(another.PathProperty('/dne', 'ec-image'))
def testSinglePhandleFollowProperty(self):
config = CrosConfig(self.filepath)
another = config.models['another']
bcs_overlay = another.PathProperty('/firmware', 'bcs-overlay')
self.assertEqual(bcs_overlay.value, 'overlay-another-private')
def testSinglePhandleFollowNode(self):
config = CrosConfig(self.filepath)
another = config.models['another']
target = another.PathProperty('/firmware/build-targets', 'coreboot')
self.assertEqual(target.value, 'another')
def testGetMergedPropertiesAnother(self):
config = CrosConfig(self.filepath)
another = config.models['another']
stylus = another.PathNode('touch/stylus')
props = another.GetMergedProperties(stylus, 'touch-type')
self.assertSequenceEqual(
props,
{'version': 'another-version',
'vendor': 'some_stylus_vendor',
'firmware-bin': '{vendor}/{version}.hex',
'firmware-symlink': '{vendor}_firmware_{MODEL}.bin'})
def testGetMergedPropertiesSome(self):
config = CrosConfig(self.filepath)
some = config.models['some']
touchscreen = some.PathNode('touch/touchscreen@0')
props = some.GetMergedProperties(touchscreen, 'touch-type')
self.assertEqual(
props,
{'pid': 'some-other-pid',
'version': 'some-other-version',
'vendor': 'some_touch_vendor',
'firmware-bin': '{vendor}/{pid}_{version}.bin',
'firmware-symlink': '{vendor}ts_i2c_{pid}.bin'})
def testGetMergedPropertiesDefault(self):
"""Test that the 'default' property is used when collecting properties"""
config = CrosConfig(self.filepath)
another = config.models['another']
audio = another.PathNode('/audio/main')
props = another.GetMergedProperties(audio, 'audio-type')
self.assertSequenceEqual(
props,
{'cras-config-dir': 'another',
'ucm-suffix': 'another',
'topology-name': 'another',
'card': 'a-card',
'volume': 'cras-config/{cras-config-dir}/{card}',
'dsp-ini': 'cras-config/{cras-config-dir}/dsp.ini',
'hifi-conf': 'ucm-config/{card}.{ucm-suffix}/HiFi.conf',
'alsa-conf': 'ucm-config/{card}.{ucm-suffix}/{card}.' +
'{ucm-suffix}.conf',
'topology-bin': 'topology/{topology-name}-tplg.bin'})
def testWriteTargetDirectories(self):
"""Test that we can write out a list of file paths"""
config = CrosConfig(self.filepath)
target_dirs = config.GetTargetDirectories()
self.assertEqual(target_dirs['dptf-dv'], '/etc/dptf')
self.assertEqual(target_dirs['hifi-conf'], '/usr/share/alsa/ucm')
self.assertEqual(target_dirs['alsa-conf'], '/usr/share/alsa/ucm')
self.assertEqual(target_dirs['volume'], '/etc/cras')
self.assertEqual(target_dirs['dsp-ini'], '/etc/cras')
self.assertEqual(target_dirs['cras-config-dir'], '/etc/cras')
def testSubmodel(self):
"""Test that we can read properties from the submodel"""
config = CrosConfig(self.filepath)
some = config.models['some']
self.assertEqual(
some.SubmodelPathProperty('touch', '/audio/main', 'ucm-suffix').value,
'some')
self.assertEqual(
some.SubmodelPathProperty('touch', '/touch', 'present').value, 'yes')
self.assertEqual(
some.SubmodelPathProperty('notouch', '/touch', 'present').value, 'no')
def testGetProperty(self):
"""Test that we can read properties from non-model nodes"""
config = CrosConfig(self.filepath)
# pylint: disable=protected-access
self.assertEqual(config._GetProperty('/chromeos/family/firmware',
'script').value, 'updater4.sh')
firmware = config.GetFamilyNode('/firmware')
self.assertEqual(firmware.name, 'firmware')
self.assertEqual(firmware.Property('script').value, 'updater4.sh')
self.assertEqual(
config.GetFamilyProperty('/firmware', 'script').value, 'updater4.sh')
def testDefaultConfig(self):
if 'SYSROOT' in os.environ:
del os.environ['SYSROOT']
with self.assertRaisesRegexp(ValueError,
'No master configuration is available'):
CrosConfig()
os.environ['SYSROOT'] = 'fred'
with self.assertRaises(IOError) as e:
CrosConfig()
self.assertIn('fred/usr/share/chromeos-config/config.dtb',
str(e.exception))
class CrosConfigHostTestYaml(unittest.TestCase, CommonTests):
"""Tests for master configuration in yaml format"""
def setUp(self):
self.filepath = os.path.join(os.path.dirname(__file__), YAML_FILE)
if __name__ == '__main__':
unittest.main()