kiwi-el8/test/unit/system/root_bind_test.py
Alexandre Detiste fb69627ad3
Use unittest.mock from core python everywhere
mock was an independent module that has been merged into the Python standard library.
2024-02-18 22:15:30 +01:00

247 lines
9.1 KiB
Python

import sys
import logging
from unittest.mock import (
patch, call, Mock
)
from pytest import (
raises, fixture
)
from ..test_helper import argv_kiwi_tests
from kiwi.system.root_bind import RootBind
from kiwi.exceptions import (
KiwiMountKernelFileSystemsError,
KiwiMountSharedDirectoryError,
KiwiSetupIntermediateConfigError
)
class TestRootBind:
@fixture(autouse=True)
def inject_fixtures(self, caplog):
self._caplog = caplog
def setup(self):
root = Mock()
root.root_dir = 'root-dir'
self.bind_root = RootBind(root)
# stub config files and bind locations
self.bind_root.config_files = ['/etc/sysconfig/proxy']
self.bind_root.bind_locations = ['/proc']
# stub files/dirs and mountpoints to cleanup
self.mount_manager = Mock()
self.bind_root.cleanup_files = ['/etc/sysconfig/proxy.kiwi']
self.bind_root.mount_stack = [self.mount_manager]
self.bind_root.dir_stack = ['/mountpoint']
def setup_method(self, cls):
self.setup()
def teardown(self):
sys.argv = argv_kiwi_tests
def teardown_method(self, cls):
self.teardown()
@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'
)
with raises(KiwiMountKernelFileSystemsError):
self.bind_root.mount_kernel_file_systems()
mock_cleanup.assert_called_once_with()
@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'
)
with raises(KiwiMountSharedDirectoryError):
self.bind_root.mount_shared_directory()
mock_cleanup.assert_called_once_with()
@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'
)
with raises(KiwiSetupIntermediateConfigError):
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_mount.return_value = shared_mount
assert self.bind_root.mount_kernel_file_systems() is None
assert mock_mount.call_args_list == [
call(device='root-dir', mountpoint='root-dir'),
call(device='/proc', mountpoint='root-dir/proc')
]
assert shared_mount.bind_mount.call_args_list == [
call(), call()
]
@patch('kiwi.system.root_bind.MountManager')
def test_umount_kernel_file_systems(self, mock_mount):
self.mount_manager.device = '/proc'
self.mount_manager.is_mounted = Mock(return_value=True)
assert self.bind_root.umount_kernel_file_systems() is None
self.mount_manager.umount_lazy.assert_called_once_with()
assert self.bind_root.mount_stack == []
@patch('kiwi.system.root_bind.MountManager')
def test_umount_kernel_file_systems_raises_error(self, mock_mount):
self.mount_manager.device = '/proc'
self.mount_manager.is_mounted = Mock(return_value=True)
self.mount_manager.umount_lazy = Mock(side_effect=Exception)
assert self.bind_root.umount_kernel_file_systems() is None
self.mount_manager.umount_lazy.assert_called_once_with()
assert self.bind_root.mount_stack == [self.mount_manager]
@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_mount.return_value = shared_mount
assert self.bind_root.mount_shared_directory() is None
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('kiwi.system.root_bind.Checksum')
@patch('os.path.exists')
def test_intermediate_config(
self, mock_exists, mock_Checksum, mock_command
):
checksum = Mock()
mock_Checksum.return_value = checksum
mock_exists.return_value = True
with patch('builtins.open') as m_open:
assert self.bind_root.setup_intermediate_config() is None
m_open.assert_called_once_with(
'root-dir/etc/sysconfig/proxy.sha', 'w'
)
assert mock_command.call_args_list == [
call([
'cp', '/etc/sysconfig/proxy', 'root-dir/etc/sysconfig/proxy.kiwi'
]),
call([
'ln', '-s', '-f', 'proxy.kiwi', 'root-dir/etc/sysconfig/proxy'
])
]
checksum.sha256.assert_called_once_with()
@patch('textwrap.dedent')
@patch('kiwi.system.root_bind.Checksum')
@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,
mock_Checksum, mock_dedent
):
checksum = Mock()
checksum.matches.return_value = False
mock_Checksum.return_value = checksum
os_exists_return_values = [False, True, True, False]
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
with self._caplog.at_level(logging.WARNING):
assert self.bind_root.cleanup() is None
self.mount_manager.umount_lazy.assert_called_once_with()
mock_remove_hierarchy.assert_called_once_with(
root='root-dir', path='/mountpoint'
)
assert mock_command.call_args_list == [
call(['rm', '-f', 'root-dir/etc/sysconfig/proxy']),
call(
[
'cp',
'root-dir/usr/share/fillup-templates/sysconfig.proxy',
'root-dir/etc/sysconfig/proxy'
]
),
call(
[
'rm', '-f', 'root-dir/etc/sysconfig/proxy.kiwi',
'root-dir/etc/sysconfig/proxy.sha'
]
)
]
mock_move.assert_called_once_with(
'root-dir/etc/sysconfig/proxy.rpmnew',
'root-dir/etc/sysconfig/proxy'
)
@patch('os.path.islink')
@patch('kiwi.command.Command.run')
@patch('kiwi.system.root_bind.Path.remove_hierarchy')
@patch('kiwi.system.root_bind.Checksum')
def test_cleanup_continue_on_error(
self, mock_Checksum, mock_remove_hierarchy,
mock_command, 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
with self._caplog.at_level(logging.WARNING):
self.bind_root.cleanup()
assert 'Image root directory root-dir not cleanly umounted:' in \
self._caplog.text
assert 'Failed to remove directory hierarchy '
'root-dir/mountpoint: rm' in self._caplog.text
assert 'Failed to cleanup intermediate config files' in \
self._caplog.text
@patch('kiwi.command.Command.run')
@patch('kiwi.system.root_bind.Path.remove_hierarchy')
@patch('kiwi.system.root_bind.Checksum')
def test_cleanup_nothing_mounted(
self, mock_Checksum, mock_remove_hierarchy, mock_command
):
self.mount_manager.is_mounted.return_value = False
self.mount_manager.mountpoint = '/mountpoint'
with self._caplog.at_level(logging.WARNING):
assert self.bind_root.cleanup() is None
assert 'Path /mountpoint not a mountpoint' in self._caplog.text