kiwi-el8/test/unit/system_root_bind_test.py
Marcus Schäfer 6b9e321048
Fixed overlay of intermediate config files
Some config files e.g etc/hosts needs to be temporary copied
from the buildsystem host to the image root system. This is
done by a custom copy with the .kiwi extension and a symlink
to that file. During the installation process the package
manager either overwrites the file or creates a .rpmnew variant.
In case a .rpmnew variant exists there is code in kiwi which
restores that .rpmnew variant to become the real file. However
that _restore_intermediate_config_rpmnew_variants() method
runs after overlay files has been applied to the system because
it's part of the final cleanup step. In order to preserve
an eventual overlay version of the file the .rpmnew variant
gets only restored if the real file does not exist.
This Fixes #807
2018-09-12 17:27:28 +02:00

184 lines
6.5 KiB
Python

from mock import patch
from mock import call
import mock
from .test_helper import raises
from kiwi.exceptions import (
KiwiMountKernelFileSystemsError,
KiwiMountSharedDirectoryError,
KiwiSetupIntermediateConfigError
)
from kiwi.system.root_bind import RootBind
class TestRootBind(object):
def setup(self):
root = mock.Mock()
root.root_dir = 'root-dir'
self.bind_root = RootBind(root)
# stub config files and bind locations
self.bind_root.config_files = ['/foo']
self.bind_root.bind_locations = ['/proc']
# stub files/dirs and mountpoints to cleanup
self.mount_manager = mock.Mock()
self.bind_root.cleanup_files = ['/foo.kiwi']
self.bind_root.mount_stack = [self.mount_manager]
self.bind_root.dir_stack = ['/mountpoint']
@raises(KiwiMountKernelFileSystemsError)
@patch('kiwi.system.root_bind.MountManager.bind_mount')
@patch('kiwi.system.root_bind.RootBind.cleanup')
@patch('os.path.exists')
def test_kernel_file_systems_raises_error(
self, mock_exists, mock_cleanup, mock_mount
):
mock_exists.return_value = True
mock_mount.side_effect = KiwiMountKernelFileSystemsError(
'mount-error'
)
self.bind_root.mount_kernel_file_systems()
mock.cleanup.assert_called_once_with()
@raises(KiwiMountSharedDirectoryError)
@patch('kiwi.system.root_bind.MountManager.bind_mount')
@patch('kiwi.system.root_bind.Path.create')
@patch('kiwi.system.root_bind.RootBind.cleanup')
def test_shared_directory_raises_error(
self, mock_cleanup, mock_path, mock_mount
):
mock_mount.side_effect = KiwiMountSharedDirectoryError(
'mount-error'
)
self.bind_root.mount_shared_directory()
mock.cleanup.assert_called_once_with()
@raises(KiwiSetupIntermediateConfigError)
@patch('kiwi.command.Command.run')
@patch('kiwi.system.root_bind.RootBind.cleanup')
@patch('os.path.exists')
def test_intermediate_config_raises_error(
self, mock_exists, mock_cleanup, mock_command
):
mock_exists.return_value = True
mock_command.side_effect = KiwiSetupIntermediateConfigError(
'config-error'
)
self.bind_root.setup_intermediate_config()
mock.cleanup.assert_called_once_with()
@patch('kiwi.system.root_bind.os.path.exists')
@patch('kiwi.system.root_bind.MountManager')
def test_mount_kernel_file_systems(self, mock_mount, mock_exists):
mock_exists.return_value = True
shared_mount = mock.Mock()
mock_mount.return_value = shared_mount
self.bind_root.mount_kernel_file_systems()
mock_mount.assert_called_once_with(
device='/proc', mountpoint='root-dir/proc'
)
shared_mount.bind_mount.assert_called_once_with()
@patch('kiwi.system.root_bind.MountManager')
@patch('kiwi.system.root_bind.Path.create')
def test_mount_shared_directory(self, mock_path, mock_mount):
shared_mount = mock.Mock()
mock_mount.return_value = shared_mount
self.bind_root.mount_shared_directory()
mock_path.call_args_list = [
call('root-dir/var/cache/kiwi'),
call('/var/cache/kiwi')
]
mock_mount.assert_called_once_with(
device='/var/cache/kiwi', mountpoint='root-dir/var/cache/kiwi'
)
shared_mount.bind_mount.assert_called_once_with()
@patch('kiwi.command.Command.run')
@patch('os.path.exists')
def test_intermediate_config(self, mock_exists, mock_command):
mock_exists.return_value = True
self.bind_root.setup_intermediate_config()
assert mock_command.call_args_list == [
call([
'cp', '/foo', 'root-dir/foo.kiwi'
]),
call([
'ln', '-s', '-f', 'foo.kiwi', 'root-dir/foo'
])
]
@patch('kiwi.system.root_bind.MountManager.is_mounted')
@patch('kiwi.system.root_bind.Command.run')
@patch('kiwi.system.root_bind.Path.remove_hierarchy')
@patch('os.path.islink')
@patch('os.path.exists')
@patch('shutil.move')
def test_cleanup(
self, mock_move, mock_exists, mock_islink, mock_remove_hierarchy,
mock_command, mock_is_mounted
):
os_exists_return_values = [False, True]
def exists_side_effect(*args):
return os_exists_return_values.pop()
mock_is_mounted.return_value = False
mock_exists.side_effect = exists_side_effect
mock_islink.return_value = True
self.bind_root.cleanup()
self.mount_manager.umount_lazy.assert_called_once_with()
mock_remove_hierarchy.assert_called_once_with('root-dir/mountpoint')
mock_command.assert_called_once_with(
['rm', '-f', 'root-dir/foo.kiwi', 'root-dir/foo']
)
mock_move.assert_called_once_with(
'root-dir/foo.rpmnew', 'root-dir/foo'
)
@patch('os.path.islink')
@patch('kiwi.logger.log.warning')
@patch('kiwi.command.Command.run')
@patch('kiwi.system.root_bind.Path.remove_hierarchy')
def test_cleanup_continue_on_error(
self, mock_remove_hierarchy, mock_command, mock_warn, mock_islink
):
mock_islink.return_value = True
mock_remove_hierarchy.side_effect = Exception('rm')
mock_command.side_effect = Exception
self.mount_manager.umount_lazy.side_effect = Exception
self.bind_root.cleanup()
assert mock_warn.call_args_list == [
call(
'Image root directory %s not cleanly umounted: %s',
'root-dir', ''
),
call(
'Failed to remove directory hierarchy root-dir/mountpoint: rm'
),
call(
'Failed to remove intermediate config files: %s', ''
)
]
@patch('kiwi.logger.log.warning')
@patch('kiwi.command.Command.run')
@patch('kiwi.system.root_bind.Path.remove_hierarchy')
def test_cleanup_nothing_mounted(
self, mock_remove_hierarchy, mock_command, mock_warn
):
self.mount_manager.is_mounted.return_value = False
self.mount_manager.mountpoint = '/mountpoint'
self.bind_root.cleanup()
mock_warn.assert_called_once_with(
'Path %s not a mountpoint', '/mountpoint'
)
def test_move_to_root(self):
assert self.bind_root.move_to_root(
[self.bind_root.root_dir + '/argument']
) == ['/argument']