kiwi-el8/test/unit/iso_test.py
Marcus Schäfer ee0f0e00fc Follow up fix for isohybrid error handling
Allow to handle multiple messages from isohybrid as warnings.
Only if the list of messages still contains information after all
non error conditions had been checked out, an exception is
thrown
2017-10-18 10:47:50 +02:00

445 lines
15 KiB
Python

from mock import call, patch
import mock
import struct
from .test_helper import raises, patch_open
import sys
from builtins import bytes
from kiwi.exceptions import (
KiwiIsoLoaderError,
KiwiIsoToolError,
KiwiIsoMetaDataError,
KiwiCommandError
)
from kiwi.iso import Iso
from collections import namedtuple
from tempfile import NamedTemporaryFile
class TestIso(object):
@patch('kiwi.iso.NamedTemporaryFile')
@patch('platform.machine')
def setup(self, mock_machine, mock_tempfile):
temp_type = namedtuple(
'temp_type', ['name']
)
mock_machine.return_value = 'x86_64'
mock_tempfile.return_value = temp_type(
name='sortfile'
)
self.context_manager_mock = mock.Mock()
self.file_mock = mock.Mock()
self.enter_mock = mock.Mock()
self.exit_mock = mock.Mock()
self.enter_mock.return_value = self.file_mock
setattr(self.context_manager_mock, '__enter__', self.enter_mock)
setattr(self.context_manager_mock, '__exit__', self.exit_mock)
self.iso = Iso('source-dir')
@patch_open
@patch('os.path.exists')
@raises(KiwiIsoLoaderError)
def test_init_iso_creation_parameters_no_loader(
self, mock_exists, mock_open
):
mock_exists.return_value = False
self.iso.init_iso_creation_parameters()
@patch('kiwi.iso.NamedTemporaryFile')
@patch('platform.machine')
def test_init_for_ix86_platform(self, mock_machine, mock_tempfile):
mock_machine.return_value = 'i686'
iso = Iso('source-dir')
assert iso.arch == 'ix86'
@patch_open
@patch('kiwi.iso.Command.run')
@patch('os.path.exists')
@patch('os.walk')
def test_init_iso_creation_parameters(
self, mock_walk, mock_exists, mock_command, mock_open
):
mock_walk_results = [
[('source-dir', ('EFI',), ())],
[('source-dir', ('bar', 'baz'), ('efi', 'eggs'))]
]
def side_effect(arg):
return mock_walk_results.pop()
mock_walk.side_effect = side_effect
mock_exists.return_value = True
mock_open.return_value = self.context_manager_mock
self.iso.init_iso_creation_parameters(['custom_arg'])
print(self.file_mock.write.call_args_list)
assert self.file_mock.write.call_args_list == [
call('7984fc91-a43f-4e45-bf27-6d3aa08b24cf\n'),
call('source-dir/boot/x86_64/boot.catalog 3\n'),
call('source-dir/boot/x86_64/loader/isolinux.bin 2\n'),
call('source-dir/efi 1000001\n'),
call('source-dir/eggs 1\n'),
call('source-dir/bar 1\n'),
call('source-dir/baz 1\n'),
call('source-dir/EFI 1\n'),
call('source-dir/header_end 1000000\n')
]
assert self.iso.iso_parameters == [
'custom_arg', '-R', '-J', '-f', '-pad', '-joliet-long',
'-sort', 'sortfile', '-no-emul-boot', '-boot-load-size', '4',
'-boot-info-table',
'-hide', 'boot/x86_64/boot.catalog',
'-hide-joliet', 'boot/x86_64/boot.catalog',
]
assert self.iso.iso_loaders == [
'-b', 'boot/x86_64/loader/isolinux.bin',
'-c', 'boot/x86_64/boot.catalog'
]
mock_command.assert_called_once_with(
[
'isolinux-config', '--base', 'boot/x86_64/loader',
'source-dir/boot/x86_64/loader/isolinux.bin'
]
)
@patch_open
@patch('kiwi.iso.Command.run')
@patch('kiwi.iso.Path.create')
@patch('os.path.exists')
@patch('os.walk')
def test_init_iso_creation_parameters_failed_isolinux_config(
self, mock_walk, mock_exists, mock_path, mock_command, mock_open
):
mock_exists.return_value = True
mock_open.return_value = self.context_manager_mock
command_raises = [False, True]
def side_effect(arg):
if command_raises.pop():
raise Exception
mock_command.side_effect = side_effect
self.iso.init_iso_creation_parameters(['custom_arg'])
mock_path.assert_called_once_with('source-dir/isolinux')
assert mock_command.call_args_list[1] == call(
[
'bash', '-c',
'ln source-dir/boot/x86_64/loader/* source-dir/isolinux'
]
)
@patch('os.path.exists')
@patch('os.path.getsize')
def test_add_efi_loader_parameters(self, mock_getsize, mock_exists):
mock_getsize.return_value = 4096
mock_exists.return_value = True
self.iso.add_efi_loader_parameters()
assert self.iso.iso_loaders == [
'-eltorito-alt-boot', '-b', 'boot/x86_64/efi',
'-no-emul-boot', '-joliet-long', '-boot-load-size', '8'
]
@patch('os.path.exists')
@patch('os.path.getsize')
def test_add_efi_loader_parameters_big_loader(
self, mock_getsize, mock_exists
):
mock_getsize.return_value = 33554432
mock_exists.return_value = True
self.iso.add_efi_loader_parameters()
assert self.iso.iso_loaders == [
'-eltorito-alt-boot', '-b', 'boot/x86_64/efi',
'-no-emul-boot', '-joliet-long'
]
def test_get_iso_creation_parameters(self):
self.iso.iso_parameters = ['a']
self.iso.iso_loaders = ['b']
assert self.iso.get_iso_creation_parameters() == ['a', 'b']
@raises(KiwiIsoToolError)
@patch('os.path.exists')
def test_isols_no_tool_found(self, mock_exists):
mock_exists.return_value = False
self.iso.isols('some-iso')
@patch('os.path.exists')
@patch('kiwi.iso.Command.run')
@patch('kiwi.iso.Path.which')
@patch_open
def test_isols_usr_bin_isoinfo_used(
self, mock_open, mock_which, mock_command, mock_exists
):
mock_which.return_value = '/usr/bin/isoinfo'
exists_results = [False, True]
def side_effect(self):
return exists_results.pop()
mock_exists.side_effect = side_effect
self.iso.isols('some-iso')
mock_command.assert_called_once_with(
['/usr/bin/isoinfo', '-R', '-l', '-i', 'some-iso']
)
@patch('os.path.exists')
@patch('kiwi.iso.Command.run')
@patch('kiwi.iso.Path.which')
@patch_open
def test_isols_usr_lib_genisoimage_isoinfo_used(
self, mock_open, mock_which, mock_command, mock_exists
):
mock_which.return_value = '/usr/lib/genisoimage/isoinfo'
exists_results = [True, False]
def side_effect(self):
return exists_results.pop()
mock_exists.side_effect = side_effect
self.iso.isols('some-iso')
mock_command.assert_called_once_with(
['/usr/lib/genisoimage/isoinfo', '-R', '-l', '-i', 'some-iso']
)
@patch('kiwi.iso.Command.run')
@patch('os.path.exists')
def test_isols(self, mock_exists, mock_command):
mock_exists.return_value = True
output_type = namedtuple('output_type', ['output'])
output_data = ''
with open('../data/iso_listing.txt') as iso:
output_data = iso.read()
mock_command.return_value = output_type(output=output_data)
result = self.iso.isols('some-iso')
assert result[2158].name == 'header_end'
def test_create_header_end_block(self):
temp_file = NamedTemporaryFile()
self.iso.header_end_file = temp_file.name
assert self.iso.create_header_end_block(
'../data/iso_with_marker.iso'
) == 96
@raises(KiwiIsoLoaderError)
def test_create_header_end_block_raises(self):
temp_file = NamedTemporaryFile()
self.iso.header_end_file = temp_file.name
self.iso.create_header_end_block(
'../data/iso_no_marker.iso'
)
@patch('kiwi.iso.Command.run')
def test_create_hybrid(self, mock_command):
mbrid = mock.Mock()
mbrid.get_id = mock.Mock(
return_value='0x0815'
)
command = mock.Mock()
command.error = None
mock_command.return_value = command
Iso.create_hybrid(42, mbrid, 'some-iso', 'efi')
mock_command.assert_called_once_with(
[
'isohybrid', '--offset', '42',
'--id', '0x0815', '--type', '0x83',
'--uefi', 'some-iso'
]
)
@raises(KiwiCommandError)
@patch('kiwi.iso.Command.run')
def test_create_hybrid_with_error(self, mock_command):
mbrid = mock.Mock()
mbrid.get_id = mock.Mock(
return_value='0x0815'
)
command = mock.Mock()
command.error = 'some error message'
mock_command.return_value = command
Iso.create_hybrid(42, mbrid, 'some-iso', 'efi')
@raises(KiwiCommandError)
@patch('kiwi.iso.Command.run')
def test_create_hybrid_with_multiple_errors(self, mock_command):
mbrid = mock.Mock()
mbrid.get_id = mock.Mock(
return_value='0x0815'
)
command = mock.Mock()
command.error = \
'isohybrid: Warning: more than 1024 cylinders: 1817\n' + \
'isohybrid: Not all BIOSes will be able to boot this device\n' + \
'isohybrid: some other error we do not ignore'
mock_command.return_value = command
Iso.create_hybrid(42, mbrid, 'some-iso', 'efi')
@patch('kiwi.iso.Command.run')
def test_create_hybrid_with_cylinders_warning(self, mock_command):
mbrid = mock.Mock()
mbrid.get_id = mock.Mock(
return_value='0x0815'
)
command = mock.Mock()
command.error = \
'isohybrid: Warning: more than 1024 cylinders: 1817\n' + \
'isohybrid: Not all BIOSes will be able to boot this device'
mock_command.return_value = command
Iso.create_hybrid(42, mbrid, 'some-iso', 'efi')
mock_command.assert_called_once_with(
[
'isohybrid', '--offset', '42',
'--id', '0x0815', '--type', '0x83',
'--uefi', 'some-iso'
]
)
@patch('kiwi.iso.Command.run')
def test_set_media_tag(self, mock_command):
Iso.set_media_tag('foo')
mock_command.assert_called_once_with(
['tagmedia', '--md5', '--check', '--pad', '150', 'foo']
)
@patch_open
@raises(KiwiIsoMetaDataError)
def test_iso_metadata_iso9660_invalid(self, mock_open):
mock_open.return_value = self.context_manager_mock
self.file_mock.read.return_value = bytes(b'bogus')
Iso.fix_boot_catalog('isofile')
@patch_open
@raises(KiwiIsoMetaDataError)
def test_iso_metadata_not_bootable(self, mock_open):
mock_open.return_value = self.context_manager_mock
self.file_mock.read.return_value = bytes(b'CD001')
Iso.fix_boot_catalog('isofile')
@patch_open
@raises(KiwiIsoMetaDataError)
def test_iso_metadata_path_table_sector_invalid(self, mock_open):
mock_open.return_value = self.context_manager_mock
read_results = [bytes(b'EL TORITO SPECIFICATION'), bytes(b'CD001')]
def side_effect(arg):
return read_results.pop()
self.file_mock.read.side_effect = side_effect
Iso.fix_boot_catalog('isofile')
@patch_open
@raises(KiwiIsoMetaDataError)
def test_iso_metadata_catalog_sector_invalid(self, mock_open):
mock_open.return_value = self.context_manager_mock
volume_descriptor = \
bytes(b'CD001') + bytes(b'_') * (0x08c - 0x5) + bytes(b'0x1d5f23a')
read_results = [bytes(b'EL TORITO SPECIFICATION'), volume_descriptor]
def side_effect(arg):
return read_results.pop()
self.file_mock.read.side_effect = side_effect
Iso.fix_boot_catalog('isofile')
@patch_open
@raises(KiwiIsoMetaDataError)
def test_iso_metadata_catalog_invalid(self, mock_open):
mock_open.return_value = self.context_manager_mock
volume_descriptor = \
bytes(b'CD001') + bytes(b'_') * (0x08c - 0x5) + bytes(b'0x1d5f23a')
eltorito_descriptor = \
bytes(b'EL TORITO SPECIFICATION') + \
bytes(b'_') * (0x47 - 0x17) + bytes(b'0x1d5f23a')
read_results = [eltorito_descriptor, volume_descriptor]
def side_effect(arg):
return read_results.pop()
self.file_mock.read.side_effect = side_effect
Iso.fix_boot_catalog('isofile')
@patch_open
def test_relocate_boot_catalog(self, mock_open):
mock_open.return_value = self.context_manager_mock
volume_descriptor = \
bytes(b'CD001') + bytes(b'_') * (0x08c - 0x5) + bytes(b'0x1d5f23a')
eltorito_descriptor = \
bytes(b'EL TORITO SPECIFICATION') + \
bytes(b'_') * (0x47 - 0x17) + bytes(b'0x1d5f23a')
new_volume_descriptor = \
bytes(b'bogus')
next_new_volume_descriptor = \
bytes(b'TEA01')
new_boot_catalog = bytes(b'\x00') * 0x800
read_results = [
new_boot_catalog,
next_new_volume_descriptor,
new_volume_descriptor,
bytes(b'catalog'),
eltorito_descriptor,
volume_descriptor
]
def side_effect(arg):
return read_results.pop()
self.file_mock.read.side_effect = side_effect
Iso.relocate_boot_catalog('isofile')
assert self.file_mock.write.call_args_list == [
call(bytes(b'catalog')),
call(
bytes(b'EL TORITO SPECIFICATION') +
bytes(b'_') * (0x47 - 0x17) + bytes(b'\x13\x00\x00\x005f23a')
)
]
@patch_open
def test_fix_boot_catalog(self, mock_open):
mock_open.return_value = self.context_manager_mock
volume_descriptor = \
bytes(b'CD001') + bytes(b'_') * (0x08c - 0x5) + bytes(b'0x1d5f23a')
eltorito_descriptor = \
bytes(b'EL TORITO SPECIFICATION') + \
bytes(b'_') * (0x47 - 0x17) + bytes(b'0x1d5f23a')
boot_catalog = bytes(b'_') * 64 + struct.pack('B', 0x88) + \
bytes(b'_') * 32
read_results = [
boot_catalog,
eltorito_descriptor,
volume_descriptor
]
def side_effect(arg):
return read_results.pop()
self.file_mock.read.side_effect = side_effect
Iso.fix_boot_catalog('isofile')
if sys.byteorder == 'big':
assert self.file_mock.write.call_args_list == [
call(
bytes(b'_') * 44 +
bytes(b'\x01Legacy (isolinux)\x00\x00\x91\xef\x00\x01') +
bytes(b'\x00') * 28 +
bytes(b'\x88___________\x01UEFI (grub)') +
bytes(b'\x00') * 8
)
]
else:
assert self.file_mock.write.call_args_list == [
call(
bytes(b'_') * 44 +
bytes(b'\x01Legacy (isolinux)\x00\x00\x91\xef\x01') +
bytes(b'\x00') * 29 +
bytes(b'\x88___________\x01UEFI (grub)') +
bytes(b'\x00') * 8
)
]