blob: 4ef2e51f596547945d4632f46254e2bcaf72ae8d [file] [log] [blame]
# Copyright 2015 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.
"""Tests for the sysroot library."""
import os
from chromite.api.gen.chromiumos import common_pb2
from chromite.lib import chroot_lib
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_test_lib
from chromite.lib import osutils
from chromite.lib import sysroot_lib
from chromite.lib import toolchain
from chromite.lib.parser import package_info
class SysrootLibTest(cros_test_lib.MockTempDirTestCase):
"""Unittest for sysroot_lib.py"""
def setUp(self):
"""Setup the test environment."""
# Fake being root to avoid running all filesystem commands with sudo_run.
self.PatchObject(os, 'getuid', return_value=0)
self.PatchObject(os, 'geteuid', return_value=0)
sysroot_path = os.path.join(self.tempdir, 'sysroot')
osutils.SafeMakedirs(sysroot_path)
self.sysroot = sysroot_lib.Sysroot(sysroot_path)
self.relative_sysroot = sysroot_lib.Sysroot('sysroot')
def _writeOverlays(self, board_overlays=None, portdir_overlays=None):
"""Helper function to write board and portdir overlays for the sysroot.
By default uses one fake board overlay, and the chromiumos and portage
stable overlays. Set the arguments to an empty list to set no values for
that field. When not explicitly set, |portdir_overlays| includes all values
in |board_overlays|.
"""
if board_overlays is None:
board_overlays = ['overlay/board']
if portdir_overlays is None:
portdir_overlays = [
constants.CHROMIUMOS_OVERLAY_DIR, constants.PORTAGE_STABLE_OVERLAY_DIR
] + board_overlays
board_field = sysroot_lib.STANDARD_FIELD_BOARD_OVERLAY
portdir_field = sysroot_lib.STANDARD_FIELD_PORTDIR_OVERLAY
board_values = [
f'{constants.CHROOT_SOURCE_ROOT}/{x}' for x in board_overlays
]
board_value = '\n'.join(board_values)
portdir_values = [
f'{constants.CHROOT_SOURCE_ROOT}/{x}' for x in portdir_overlays
]
portdir_value = '\n'.join(portdir_values)
config_values = {}
if board_values:
config_values[board_field] = board_value
if portdir_values:
config_values[portdir_field] = portdir_value
config = '\n'.join(f'{k}="{v}"' for k, v in config_values.items())
self.sysroot.WriteConfig(config)
return board_values, portdir_values
def testGetStandardField(self):
"""Tests that standard field can be fetched correctly."""
self.sysroot.WriteConfig('FOO="bar"')
self.assertEqual('bar', self.sysroot.GetStandardField('FOO'))
# Works with multiline strings
multiline = """foo
bar
baz
"""
self.sysroot.WriteConfig('TEST="%s"' % multiline)
self.assertEqual(multiline, self.sysroot.GetStandardField('TEST'))
def testReadWriteCache(self):
"""Tests that we can write and read to the cache."""
# If a field is not defined we get None.
self.assertEqual(None, self.sysroot.GetCachedField('foo'))
# If we set a field, we can get it.
self.sysroot.SetCachedField('foo', 'bar')
self.assertEqual('bar', self.sysroot.GetCachedField('foo'))
# Setting a field in an existing cache preserve the previous values.
self.sysroot.SetCachedField('hello', 'bonjour')
self.assertEqual('bar', self.sysroot.GetCachedField('foo'))
self.assertEqual('bonjour', self.sysroot.GetCachedField('hello'))
# Setting a field to None unsets it.
self.sysroot.SetCachedField('hello', None)
self.assertEqual(None, self.sysroot.GetCachedField('hello'))
def testErrorOnBadCachedValue(self):
"""Tests that we detect bad value for the sysroot cache."""
forbidden = [
'hello"bonjour',
'hello\\bonjour',
'hello\nbonjour',
'hello$bonjour',
'hello`bonjour',
]
for value in forbidden:
with self.assertRaises(ValueError):
self.sysroot.SetCachedField('FOO', value)
def testGenerateConfigNoToolchainRaisesError(self):
"""Tests _GenerateConfig() with no toolchain raises an error."""
self.PatchObject(toolchain, 'FilterToolchains', autospec=True,
return_value={})
with self.assertRaises(sysroot_lib.ConfigurationError):
# pylint: disable=protected-access
self.sysroot._GenerateConfig({}, ['foo_overlay'], ['foo_overlay'], '')
def testExists(self):
"""Tests the Exists method."""
self.assertTrue(self.sysroot.Exists())
dne_sysroot = sysroot_lib.Sysroot(os.path.join(self.tempdir, 'DNE'))
self.assertFalse(dne_sysroot.Exists())
def testExistsInChroot(self):
"""Test the Exists method with a chroot."""
chroot = chroot_lib.Chroot(self.tempdir)
self.assertTrue(self.relative_sysroot.Exists(chroot=chroot))
def testEquals(self):
"""Sanity check for the __eq__ methods."""
sysroot1 = sysroot_lib.Sysroot(self.tempdir)
sysroot2 = sysroot_lib.Sysroot(self.tempdir)
self.assertEqual(sysroot1, sysroot2)
def testProfileName(self):
"""Test the profile_name property when a value is set."""
profile = 'foo'
self.sysroot.SetCachedField(sysroot_lib.CACHED_FIELD_PROFILE_OVERRIDE,
profile)
self.assertEqual(profile, self.sysroot.profile_name)
def testProfileNameDefault(self):
"""Test the profile_name property when no value is set."""
self.assertEqual(sysroot_lib.DEFAULT_PROFILE, self.sysroot.profile_name)
def testBoardOverlay(self):
"""Test the board_overlay property."""
board_overlays, _portdir_overlays = self._writeOverlays()
self.assertEqual(board_overlays, self.sysroot.build_target_overlays)
def testOverlays(self):
"""Test the overlays property."""
_board_overlays, portdir_overlays = self._writeOverlays()
self.assertEqual(portdir_overlays, self.sysroot.overlays)
def testGetOverlays(self):
"""Test the get_overlays function."""
board_overlays, portdir_overlays = self._writeOverlays()
self.assertEqual(
board_overlays,
[str(x) for x in self.sysroot.get_overlays(build_target_only=True)])
self.assertEqual(portdir_overlays,
[str(x) for x in self.sysroot.get_overlays()])
def testGetOverlaysRelative(self):
portdir_overlays = [
constants.CHROMIUMOS_OVERLAY_DIR, constants.PORTAGE_STABLE_OVERLAY_DIR
]
self._writeOverlays(portdir_overlays=portdir_overlays)
self.assertEqual(portdir_overlays,
[str(x) for x in self.sysroot.get_overlays(relative=True)])
class ProfileTest(cros_test_lib.MockTempDirTestCase):
"""Unittest for sysroot_lib.py"""
def testConversion(self):
"""Test converting to/from protobuf."""
profile1 = sysroot_lib.Profile('profile')
profile2 = sysroot_lib.Profile()
proto1 = common_pb2.Profile(name='profile')
proto2 = common_pb2.Profile()
self.assertEqual(profile1.as_protobuf, proto1)
self.assertEqual(profile2.as_protobuf, proto2)
self.assertEqual(profile1, sysroot_lib.Profile.from_protobuf(proto1))
self.assertEqual(profile2, sysroot_lib.Profile.from_protobuf(proto2))
def testEquality(self):
"""Test that equality functions work."""
profile = sysroot_lib.Profile('profile')
self.assertEqual(profile, sysroot_lib.Profile('profile'))
self.assertNotEqual(profile, sysroot_lib.Profile('other'))
self.assertNotEqual(profile, sysroot_lib.Profile(''))
class SysrootLibInstallConfigTest(cros_test_lib.MockTempDirTestCase):
"""Unittest for sysroot_lib.py"""
# pylint: disable=protected-access
def setUp(self):
"""Setup the test environment."""
# Fake being root to avoid running all filesystem commands with sudo_run.
self.PatchObject(os, 'getuid', return_value=0)
self.PatchObject(os, 'geteuid', return_value=0)
self.sysroot = sysroot_lib.Sysroot(self.tempdir)
self.make_conf_generic_target = os.path.join(self.tempdir,
'make.conf.generic-target')
self.make_conf_user = os.path.join(self.tempdir, 'make.conf.user')
D = cros_test_lib.Directory
filesystem = (
D('etc', ()),
'make.conf.generic-target',
'make.conf.user',
)
cros_test_lib.CreateOnDiskHierarchy(self.tempdir, filesystem)
def testInstallMakeConf(self):
"""Test make.conf installation."""
self.PatchObject(sysroot_lib, '_GetMakeConfGenericPath',
return_value=self.make_conf_generic_target)
self.sysroot.InstallMakeConf()
filepath = os.path.join(self.tempdir, sysroot_lib._MAKE_CONF)
self.assertExists(filepath)
def testInstallMakeConfBoard(self):
"""Test make.conf.board installation."""
self.PatchObject(self.sysroot, 'GenerateBoardMakeConf', return_value='#foo')
self.PatchObject(self.sysroot, 'GenerateBinhostConf', return_value='#bar')
self.sysroot.InstallMakeConfBoard()
filepath = os.path.join(self.tempdir, sysroot_lib._MAKE_CONF_BOARD)
content = '#foo\n#bar\n'
self.assertExists(filepath)
self.assertFileContents(filepath, content)
def testInstallMakeConfBoardSetup(self):
"""Test make.conf.board_setup installation."""
self.PatchObject(self.sysroot, 'GenerateBoardSetupConfig',
return_value='#foo')
self.sysroot.InstallMakeConfBoardSetup('board')
filepath = os.path.join(self.tempdir, sysroot_lib._MAKE_CONF_BOARD_SETUP)
content = '#foo'
self.assertExists(filepath)
self.assertFileContents(filepath, content)
def testInstallMakeConfUser(self):
"""Test make.conf.user installation."""
self.PatchObject(sysroot_lib, '_GetChrootMakeConfUserPath',
return_value=self.make_conf_user)
self.sysroot.InstallMakeConfUser()
filepath = os.path.join(self.tempdir, sysroot_lib._MAKE_CONF_USER)
self.assertExists(filepath)
class SysrootLibToolchainUpdateTest(cros_test_lib.RunCommandTempDirTestCase):
"""Sysroot.ToolchanUpdate tests."""
def setUp(self):
"""Setup the test environment."""
# Fake being root to avoid running commands with sudo_run.
self.PatchObject(os, 'getuid', return_value=0)
self.PatchObject(os, 'geteuid', return_value=0)
self.sysroot = sysroot_lib.Sysroot(self.tempdir)
self.emerge = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
def testDefaultUpdateToolchain(self):
"""Test the default path."""
self.PatchObject(toolchain, 'InstallToolchain')
self.sysroot.UpdateToolchain('board')
self.assertCommandContains(
[self.emerge, '--board=board', '--getbinpkg', '--usepkg'])
def testNoLocalInitUpdateToolchain(self):
"""Test the nousepkg and not local case."""
self.PatchObject(toolchain, 'InstallToolchain')
self.sysroot.UpdateToolchain('board', local_init=False)
self.assertCommandContains(['--getbinpkg', '--usepkg'], expected=False)
self.assertCommandContains([self.emerge, '--board=board'])
def testReUpdateToolchain(self):
"""Test behavior when not running for the first time."""
self.PatchObject(toolchain, 'InstallToolchain')
self.PatchObject(self.sysroot, 'IsToolchainInstalled', return_value=True)
self.sysroot.UpdateToolchain('board')
self.assertCommandContains([self.emerge], expected=False)
def testInstallToolchainError(self):
"""Test error handling from the libc install."""
failed = ['cat/pkg', 'cat/pkg2']
failed_pkgs = [package_info.parse(pkg) for pkg in failed]
result = cros_build_lib.CommandResult(returncode=1)
error = toolchain.ToolchainInstallError('Error', result=result,
tc_info=failed_pkgs)
self.PatchObject(toolchain, 'InstallToolchain', side_effect=error)
try:
self.sysroot.UpdateToolchain('board')
except sysroot_lib.ToolchainInstallError as e:
self.assertTrue(e.failed_toolchain_info)
self.assertEqual(failed_pkgs, e.failed_toolchain_info)
except Exception as e:
self.fail('Unexpected exception raised: %s' % type(e))
else:
self.fail('Expected an exception.')
def testEmergeError(self):
"""Test the emerge error handling."""
self.PatchObject(toolchain, 'InstallToolchain')
# pylint: disable=protected-access
command = self.sysroot._UpdateToolchainCommand('board', True)
err = cros_build_lib.RunCommandError(
'Error', cros_build_lib.CommandResult(returncode=1))
self.rc.AddCmdResult(command, side_effect=err)
with self.assertRaises(sysroot_lib.ToolchainInstallError):
self.sysroot.UpdateToolchain('board', local_init=True)
def test_get_sdk_provided_packages(simple_sysroot):
pkg_provided = simple_sysroot.path / 'etc/portage/profile/package.provided'
content = """
foo/bar-2-r3
# Comment line.
cat/pkg-1.0.0 # Comment after package.
"""
osutils.WriteFile(pkg_provided, content, makedirs=True)
pkgs = list(sysroot_lib.get_sdk_provided_packages(simple_sysroot.path))
expected = [package_info.parse(p) for p in ('foo/bar-2-r3', 'cat/pkg-1.0.0')]
assert pkgs == expected