mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-15 17:34:43 +00:00
Merge patch series "Improve pytest runtime"
Tom Rini <trini@konsulko.com> says: One thing that Simon Glass has noted is that our pytest run time keeps getting longer. Looking at: https://source.denx.de/u-boot/u-boot/-/pipelines/25011/test_report?job_name=sandbox%20test.py%3A%20%5Bfast%20amd64%5D we can see that some of the longest running tests are a little puzzling. It turns out that we have two ways of making filesystem images without requiring root access and one of them is significantly slower than the other. This series changes us from using virt-make-fs to only using the mk_fs helper that currently resides in test_ut.py which uses standard userspace tools. The final result can be seen at: https://source.denx.de/u-boot/u-boot/-/pipelines/25015/test_report?job_name=sandbox%20test.py%3A%20%5Bfast%20amd64%5D and the tests changed here now run much quicker. Link: https://lore.kernel.org/r/20250320140030.2052434-1-trini@konsulko.com
This commit is contained in:
commit
a30b544628
18 changed files with 288 additions and 350 deletions
|
@ -41,13 +41,11 @@ will be required. The following is an incomplete list:
|
|||
* dfu-util
|
||||
* dtc
|
||||
* openssl
|
||||
* sudo OR guestmount
|
||||
* e2fsprogs
|
||||
* util-linux
|
||||
* coreutils
|
||||
* dosfstools
|
||||
* efitools
|
||||
* guestfs-tools
|
||||
* mount
|
||||
* mtools
|
||||
* sbsigntool
|
||||
|
@ -64,23 +62,12 @@ The test script supports either:
|
|||
physical board, attach to the board's console stream, and reset the board.
|
||||
Further details are described later.
|
||||
|
||||
The usage of command 'sudo' should be avoided in tests. To create disk images
|
||||
use command virt-make-fs which is provided by package guestfs-tools. This
|
||||
command creates a virtual machine with QEMU in which the disk image is
|
||||
generated.
|
||||
|
||||
Command virt-make-fs needs read access to the current kernel. On Ubuntu only
|
||||
root has this privilege. You can add a script /etc/initramfs-tools/hooks/vmlinuz
|
||||
with the following content to overcome the problem:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/bin/sh
|
||||
echo "chmod a+r vmlinuz-*"
|
||||
chmod a+r /boot/vmlinuz-*
|
||||
|
||||
The script should be chmod 755. It will be invoked whenever the initial RAM file
|
||||
system is updated.
|
||||
The usage of the command 'sudo' is not allowed in tests. Using elevated
|
||||
priviledges can lead to security concerns. Furthermore not all users may have
|
||||
administrator rights. Therefore the command 'sudo' must not be used in tests.
|
||||
To create disk images we have helper functions located in
|
||||
`test/py/tests/fs_helper.py` which shall be used in any tests that require
|
||||
creating disk images.
|
||||
|
||||
Using `virtualenv` to provide requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -73,6 +73,40 @@ def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
|
|||
call(f'rm -f {fs_img}', shell=True)
|
||||
raise
|
||||
|
||||
def setup_image(ubman, devnum, part_type, img_size=20, second_part=False,
|
||||
basename='mmc'):
|
||||
"""Create a disk image with a single partition
|
||||
|
||||
Args:
|
||||
ubman (ConsoleBase): Console to use
|
||||
devnum (int): Device number to use, e.g. 1
|
||||
part_type (int): Partition type, e.g. 0xc for FAT32
|
||||
img_size (int): Image size in MiB
|
||||
second_part (bool): True to contain a small second partition
|
||||
basename (str): Base name to use in the filename, e.g. 'mmc'
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
str: Filename of MMC image
|
||||
str: Directory name of scratch directory
|
||||
"""
|
||||
fname = os.path.join(ubman.config.source_dir, f'{basename}{devnum}.img')
|
||||
mnt = os.path.join(ubman.config.persistent_data_dir, 'scratch')
|
||||
|
||||
spec = f'type={part_type:x}, size={img_size - 2}M, start=1M, bootable'
|
||||
if second_part:
|
||||
spec += '\ntype=c'
|
||||
|
||||
try:
|
||||
check_call(f'mkdir -p {mnt}', shell=True)
|
||||
check_call(f'qemu-img create {fname} {img_size}M', shell=True)
|
||||
check_call(f'printf "{spec}" | sfdisk {fname}', shell=True)
|
||||
except CalledProcessError:
|
||||
call(f'rm -f {fname}', shell=True)
|
||||
raise
|
||||
|
||||
return fname, mnt
|
||||
|
||||
# Just for trying out
|
||||
if __name__ == "__main__":
|
||||
import collections
|
||||
|
|
37
test/py/tests/test_cat.py
Normal file
37
test/py/tests/test_cat.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
""" Unit test for cat command
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_cat')
|
||||
def test_cat(ubman):
|
||||
""" Unit test for cat
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
"""
|
||||
try:
|
||||
scratch_dir = ubman.config.persistent_data_dir + '/scratch'
|
||||
|
||||
check_call('mkdir -p %s' % scratch_dir, shell=True)
|
||||
|
||||
with open(scratch_dir + '/hello', 'w', encoding = 'ascii') as file:
|
||||
file.write('hello world\n')
|
||||
|
||||
cat_data = fs_helper.mk_fs(ubman.config, 'vfat', 0x100000,
|
||||
'test_cat', scratch_dir)
|
||||
response = ubman.run_command_list([ f'host bind 0 {cat_data}',
|
||||
'cat host 0 hello'])
|
||||
assert 'hello world' in response
|
||||
except CalledProcessError as err:
|
||||
pytest.skip('Preparing test_cat image failed')
|
||||
call('rm -f %s' % cat_data, shell=True)
|
||||
return
|
||||
finally:
|
||||
call('rm -rf %s' % scratch_dir, shell=True)
|
||||
call('rm -f %s' % cat_data, shell=True)
|
|
@ -1,36 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
"""Fixture for cat command test
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from subprocess import check_call, CalledProcessError
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def cat_data(u_boot_config):
|
||||
"""Set up a file system to be used in cat tests
|
||||
|
||||
Args:
|
||||
u_boot_config -- U-Boot configuration.
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_cat'
|
||||
image_path = u_boot_config.persistent_data_dir + '/cat.img'
|
||||
|
||||
try:
|
||||
os.mkdir(mnt_point, mode = 0o755)
|
||||
|
||||
with open(mnt_point + '/hello', 'w', encoding = 'ascii') as file:
|
||||
file.write('hello world\n')
|
||||
|
||||
check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}',
|
||||
shell=True)
|
||||
|
||||
yield image_path
|
||||
except CalledProcessError:
|
||||
pytest.skip('Setup failed')
|
||||
finally:
|
||||
shutil.rmtree(mnt_point)
|
||||
if os.path.exists(image_path):
|
||||
os.remove(image_path)
|
|
@ -1,20 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
""" Unit test for cat command
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_cat')
|
||||
def test_cat(ubman, cat_data):
|
||||
""" Unit test for cat
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
cat_data -- Path to the disk image used for testing.
|
||||
"""
|
||||
response = ubman.run_command_list([
|
||||
f'host bind 0 {cat_data}',
|
||||
'cat host 0 hello'])
|
||||
assert 'hello world' in response
|
70
test/py/tests/test_efi_bootmgr.py
Normal file
70
test/py/tests/test_efi_bootmgr.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
""" Unit test for UEFI bootmanager
|
||||
"""
|
||||
|
||||
import shutil
|
||||
import pytest
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_efidebug')
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_bootmgr')
|
||||
@pytest.mark.singlethread
|
||||
def test_efi_bootmgr(ubman):
|
||||
""" Unit test for UEFI bootmanager
|
||||
The efidebug command is used to set up UEFI load options.
|
||||
The bootefi bootmgr loads initrddump.efi as a payload.
|
||||
The crc32 of the loaded initrd.img is checked
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
"""
|
||||
try:
|
||||
efi_bootmgr_data, mnt = fs_helper.setup_image(ubman, 0, 0xc,
|
||||
basename='test_efi_bootmgr')
|
||||
|
||||
with open(mnt + '/initrd-1.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 1")
|
||||
|
||||
with open(mnt + '/initrd-2.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 2")
|
||||
|
||||
shutil.copyfile(ubman.config.build_dir + '/lib/efi_loader/initrddump.efi',
|
||||
mnt + '/initrddump.efi')
|
||||
|
||||
fsfile = fs_helper.mk_fs(ubman.config, 'vfat', 0x100000,
|
||||
'test_efi_bootmgr', mnt)
|
||||
check_call(f'dd if={fsfile} of={efi_bootmgr_data} bs=1M seek=1', shell=True)
|
||||
|
||||
ubman.run_command(cmd = f'host bind 0 {efi_bootmgr_data}')
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot add ' \
|
||||
'-b 0001 label-1 host 0:1 initrddump.efi ' \
|
||||
'-i host 0:1 initrd-1.img -s nocolor')
|
||||
ubman.run_command(cmd = 'efidebug boot dump')
|
||||
ubman.run_command(cmd = 'efidebug boot order 0001')
|
||||
ubman.run_command(cmd = 'bootefi bootmgr')
|
||||
response = ubman.run_command(cmd = 'load', wait_for_echo=False)
|
||||
assert 'crc32: 0x181464af' in response
|
||||
ubman.run_command(cmd = 'exit', wait_for_echo=False)
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot add ' \
|
||||
'-B 0002 label-2 host 0:1 initrddump.efi ' \
|
||||
'-I host 0:1 initrd-2.img -s nocolor')
|
||||
ubman.run_command(cmd = 'efidebug boot dump')
|
||||
ubman.run_command(cmd = 'efidebug boot order 0002')
|
||||
ubman.run_command(cmd = 'bootefi bootmgr')
|
||||
response = ubman.run_command(cmd = 'load', wait_for_echo=False)
|
||||
assert 'crc32: 0x811d3515' in response
|
||||
ubman.run_command(cmd = 'exit', wait_for_echo=False)
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot rm 0001')
|
||||
ubman.run_command(cmd = 'efidebug boot rm 0002')
|
||||
except CalledProcessError as err:
|
||||
pytest.skip('Preparing test_efi_bootmgr image failed')
|
||||
call('rm -f %s' % efi_bootmgr_data, shell=True)
|
||||
return
|
||||
finally:
|
||||
call('rm -rf %s' % mnt, shell=True)
|
||||
call('rm -f %s' % efi_bootmgr_data, shell=True)
|
|
@ -1,38 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
"""Fixture for UEFI bootmanager test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from subprocess import check_call
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def efi_bootmgr_data(u_boot_config):
|
||||
"""Set up a file system to be used in UEFI bootmanager tests.
|
||||
|
||||
Args:
|
||||
u_boot_config -- U-Boot configuration.
|
||||
|
||||
Return:
|
||||
A path to disk image to be used for testing
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_efi_bootmgr'
|
||||
image_path = u_boot_config.persistent_data_dir + '/efi_bootmgr.img'
|
||||
|
||||
shutil.rmtree(mnt_point, ignore_errors=True)
|
||||
os.mkdir(mnt_point, mode = 0o755)
|
||||
|
||||
with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 1")
|
||||
|
||||
with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 2")
|
||||
|
||||
shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi',
|
||||
mnt_point + '/initrddump.efi')
|
||||
|
||||
check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}',
|
||||
shell=True)
|
||||
|
||||
return image_path
|
|
@ -1,44 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
""" Unit test for UEFI bootmanager
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_efidebug')
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_bootmgr')
|
||||
@pytest.mark.singlethread
|
||||
def test_efi_bootmgr(ubman, efi_bootmgr_data):
|
||||
""" Unit test for UEFI bootmanager
|
||||
The efidebug command is used to set up UEFI load options.
|
||||
The bootefi bootmgr loads initrddump.efi as a payload.
|
||||
The crc32 of the loaded initrd.img is checked
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
efi_bootmgr_data -- Path to the disk image used for testing.
|
||||
"""
|
||||
ubman.run_command(cmd = f'host bind 0 {efi_bootmgr_data}')
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot add ' \
|
||||
'-b 0001 label-1 host 0:1 initrddump.efi ' \
|
||||
'-i host 0:1 initrd-1.img -s nocolor')
|
||||
ubman.run_command(cmd = 'efidebug boot dump')
|
||||
ubman.run_command(cmd = 'efidebug boot order 0001')
|
||||
ubman.run_command(cmd = 'bootefi bootmgr')
|
||||
response = ubman.run_command(cmd = 'load', wait_for_echo=False)
|
||||
assert 'crc32: 0x181464af' in response
|
||||
ubman.run_command(cmd = 'exit', wait_for_echo=False)
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot add ' \
|
||||
'-B 0002 label-2 host 0:1 initrddump.efi ' \
|
||||
'-I host 0:1 initrd-2.img -s nocolor')
|
||||
ubman.run_command(cmd = 'efidebug boot dump')
|
||||
ubman.run_command(cmd = 'efidebug boot order 0002')
|
||||
ubman.run_command(cmd = 'bootefi bootmgr')
|
||||
response = ubman.run_command(cmd = 'load', wait_for_echo=False)
|
||||
assert 'crc32: 0x811d3515' in response
|
||||
ubman.run_command(cmd = 'exit', wait_for_echo=False)
|
||||
|
||||
ubman.run_command(cmd = 'efidebug boot rm 0001')
|
||||
ubman.run_command(cmd = 'efidebug boot rm 0002')
|
|
@ -136,7 +136,7 @@ def do_reboot_dtb_specified(u_boot_config, ubman, dtb_filename):
|
|||
ubman -- A console connection to U-Boot.
|
||||
dtb_filename -- DTB file name.
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/scratch'
|
||||
ubman.config.dtb = mnt_point + CAPSULE_DATA_DIR \
|
||||
+ f'/{dtb_filename}'
|
||||
ubman.restart_uboot()
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
import os
|
||||
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
import pytest
|
||||
from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR, EFITOOLS_PATH
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def efi_capsule_data(request, u_boot_config):
|
||||
@pytest.fixture(scope='function')
|
||||
def efi_capsule_data(request, ubman):
|
||||
"""Set up a file system and return path to image.
|
||||
|
||||
The function sets up a file system to be used in UEFI capsule and
|
||||
|
@ -19,14 +20,14 @@ def efi_capsule_data(request, u_boot_config):
|
|||
for testing.
|
||||
|
||||
request -- Pytest request object.
|
||||
u_boot_config -- U-Boot configuration.
|
||||
ubman -- U-Boot configuration.
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
|
||||
data_dir = mnt_point + CAPSULE_DATA_DIR
|
||||
install_dir = mnt_point + CAPSULE_INSTALL_DIR
|
||||
image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
|
||||
|
||||
try:
|
||||
image_path, mnt_point = fs_helper.setup_image(ubman, 0, 0xc,
|
||||
basename='test_efi_capsule')
|
||||
data_dir = mnt_point + CAPSULE_DATA_DIR
|
||||
install_dir = mnt_point + CAPSULE_INSTALL_DIR
|
||||
|
||||
# Create a target device
|
||||
check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
|
||||
|
||||
|
@ -34,9 +35,9 @@ def efi_capsule_data(request, u_boot_config):
|
|||
check_call('mkdir -p %s' % data_dir, shell=True)
|
||||
check_call('mkdir -p %s' % install_dir, shell=True)
|
||||
|
||||
capsule_auth_enabled = u_boot_config.buildconfig.get(
|
||||
capsule_auth_enabled = ubman.config.buildconfig.get(
|
||||
'config_efi_capsule_authenticate')
|
||||
key_dir = u_boot_config.source_dir + '/board/sandbox'
|
||||
key_dir = ubman.config.source_dir + '/board/sandbox'
|
||||
if capsule_auth_enabled:
|
||||
# Get the keys from the board directory
|
||||
check_call('cp %s/capsule_priv_key_good.key %s/SIGNER.key'
|
||||
|
@ -54,12 +55,12 @@ def efi_capsule_data(request, u_boot_config):
|
|||
# Update dtb to add the version information
|
||||
check_call('cd %s; '
|
||||
'cp %s/test/py/tests/test_efi_capsule/version.dtso .'
|
||||
% (data_dir, u_boot_config.source_dir), shell=True)
|
||||
% (data_dir, ubman.config.source_dir), shell=True)
|
||||
|
||||
if capsule_auth_enabled:
|
||||
check_call('cd %s; '
|
||||
'cp %s/arch/sandbox/dts/test.dtb test_sig.dtb'
|
||||
% (data_dir, u_boot_config.build_dir), shell=True)
|
||||
% (data_dir, ubman.config.build_dir), shell=True)
|
||||
check_call('cd %s; '
|
||||
'dtc -@ -I dts -O dtb -o version.dtbo version.dtso; '
|
||||
'fdtoverlay -i test_sig.dtb '
|
||||
|
@ -70,29 +71,33 @@ def efi_capsule_data(request, u_boot_config):
|
|||
'dtc -@ -I dts -O dtb -o version.dtbo version.dtso; '
|
||||
'fdtoverlay -i %s/arch/sandbox/dts/test.dtb '
|
||||
'-o test_ver.dtb version.dtbo'
|
||||
% (data_dir, u_boot_config.build_dir), shell=True)
|
||||
% (data_dir, ubman.config.build_dir), shell=True)
|
||||
|
||||
# two regions: one for u-boot.bin and the other for u-boot.env
|
||||
check_call('cd %s; echo -n u-boot:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old > u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,
|
||||
shell=True)
|
||||
|
||||
pythonpath = os.environ.get('PYTHONPATH', '')
|
||||
os.environ['PYTHONPATH'] = pythonpath + ':' + '%s/scripts/dtc/pylibfdt' % u_boot_config.build_dir
|
||||
os.environ['PYTHONPATH'] = pythonpath + ':' + '%s/scripts/dtc/pylibfdt' % ubman.config.build_dir
|
||||
check_call('cd %s; '
|
||||
'cc -E -I %s/include -x assembler-with-cpp -o capsule_gen_tmp.dts %s/test/py/tests/test_efi_capsule/capsule_gen_binman.dts; '
|
||||
'dtc -I dts -O dtb capsule_gen_tmp.dts -o capsule_binman.dtb;'
|
||||
% (data_dir, u_boot_config.source_dir, u_boot_config.source_dir), shell=True)
|
||||
% (data_dir, ubman.config.source_dir, ubman.config.source_dir), shell=True)
|
||||
check_call('cd %s; '
|
||||
'./tools/binman/binman --toolpath %s/tools build -u -d %s/capsule_binman.dtb -O %s -m --allow-missing -I %s -I ./board/sandbox -I ./arch/sandbox/dts'
|
||||
% (u_boot_config.source_dir, u_boot_config.build_dir, data_dir, data_dir, data_dir), shell=True)
|
||||
check_call('cp %s/Test* %s' % (u_boot_config.build_dir, data_dir), shell=True)
|
||||
% (ubman.config.source_dir, ubman.config.build_dir, data_dir, data_dir, data_dir), shell=True)
|
||||
check_call('cp %s/Test* %s' % (ubman.config.build_dir, data_dir), shell=True)
|
||||
os.environ['PYTHONPATH'] = pythonpath
|
||||
|
||||
# Create a disk image with EFI system partition
|
||||
check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
|
||||
(mnt_point, image_path), shell=True)
|
||||
# Create a 16MiB partition as the EFI system partition in the disk
|
||||
# image
|
||||
fsfile = fs_helper.mk_fs(ubman.config, 'vfat', 0x1000000,
|
||||
'test_efi_capsule', mnt_point)
|
||||
check_call(f'dd conv=notrunc if={fsfile} of={image_path} bs=1M seek=1', shell=True)
|
||||
check_call('sgdisk --mbrtogpt %s' % image_path, shell=True)
|
||||
check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
|
||||
image_path, shell=True)
|
||||
call('rm -f %s' % fsfile, shell=True)
|
||||
|
||||
except CalledProcessError as exception:
|
||||
pytest.skip('Setup failed: %s' % exception.cmd)
|
||||
|
|
|
@ -5,27 +5,25 @@
|
|||
"""Fixture for UEFI secure boot test."""
|
||||
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
import pytest
|
||||
from defs import *
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def efi_boot_env(request, u_boot_config):
|
||||
@pytest.fixture(scope='function')
|
||||
def efi_boot_env(request, ubman):
|
||||
"""Set up a file system to be used in UEFI secure boot test.
|
||||
|
||||
Args:
|
||||
request: Pytest request object.
|
||||
u_boot_config: U-Boot configuration.
|
||||
ubman: U-Boot configuration.
|
||||
|
||||
Return:
|
||||
A path to disk image to be used for testing
|
||||
"""
|
||||
image_path = u_boot_config.persistent_data_dir
|
||||
image_path = image_path + '/test_efi_secboot.img'
|
||||
|
||||
try:
|
||||
mnt_point = u_boot_config.build_dir + '/mnt_efisecure'
|
||||
check_call('rm -rf {}'.format(mnt_point), shell=True)
|
||||
check_call('mkdir -p {}'.format(mnt_point), shell=True)
|
||||
image_path, mnt_point = fs_helper.setup_image(ubman, 0, 0xc,
|
||||
basename='test_efi_secboot')
|
||||
|
||||
# suffix
|
||||
# *.key: RSA private key in PEM
|
||||
|
@ -101,7 +99,7 @@ def efi_boot_env(request, u_boot_config):
|
|||
|
||||
# Copy image
|
||||
check_call('cp %s/lib/efi_loader/helloworld.efi %s' %
|
||||
(u_boot_config.build_dir, mnt_point), shell=True)
|
||||
(ubman.config.build_dir, mnt_point), shell=True)
|
||||
|
||||
# Sign image
|
||||
check_call('cd %s; sbsign --key db.key --cert db.crt helloworld.efi'
|
||||
|
@ -111,7 +109,7 @@ def efi_boot_env(request, u_boot_config):
|
|||
% mnt_point, shell=True)
|
||||
# Create a corrupted signed image
|
||||
check_call('cd %s; sh %s/test/py/tests/test_efi_secboot/forge_image.sh helloworld.efi.signed helloworld_forged.efi.signed'
|
||||
% (mnt_point, u_boot_config.source_dir), shell=True)
|
||||
% (mnt_point, ubman.config.source_dir), shell=True)
|
||||
# Digest image
|
||||
check_call('cd %s; %shash-to-efi-sig-list helloworld.efi db_hello.hash; %ssign-efi-sig-list -t "2020-04-07" -c KEK.crt -k KEK.key db db_hello.hash db_hello.auth'
|
||||
% (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH),
|
||||
|
@ -123,9 +121,9 @@ def efi_boot_env(request, u_boot_config):
|
|||
% (mnt_point, EFITOOLS_PATH),
|
||||
shell=True)
|
||||
|
||||
check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'.format(
|
||||
mnt_point, image_path), shell=True)
|
||||
check_call('rm -rf {}'.format(mnt_point), shell=True)
|
||||
fsfile = fs_helper.mk_fs(ubman.config, 'vfat', 0x1000000,
|
||||
'test_efi_secboot', mnt_point)
|
||||
check_call(f'dd if={fsfile} of={image_path} bs=1M seek=1', shell=True)
|
||||
|
||||
except CalledProcessError as exception:
|
||||
pytest.skip('Setup failed: %s' % exception.cmd)
|
||||
|
@ -133,15 +131,16 @@ def efi_boot_env(request, u_boot_config):
|
|||
else:
|
||||
yield image_path
|
||||
finally:
|
||||
call('rm -f %s' % image_path, shell=True)
|
||||
call('rm -rf %s' % mnt_point, shell=True)
|
||||
call('rm -f %s %s' % (image_path, fsfile), shell=True)
|
||||
|
||||
#
|
||||
# Fixture for UEFI secure boot test of intermediate certificates
|
||||
#
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def efi_boot_env_intca(request, u_boot_config):
|
||||
@pytest.fixture(scope='function')
|
||||
def efi_boot_env_intca(request, ubman):
|
||||
"""Set up file system for secure boot test.
|
||||
|
||||
Set up a file system to be used in UEFI secure boot test
|
||||
|
@ -149,18 +148,15 @@ def efi_boot_env_intca(request, u_boot_config):
|
|||
|
||||
Args:
|
||||
request: Pytest request object.
|
||||
u_boot_config: U-Boot configuration.
|
||||
ubman: U-Boot configuration.
|
||||
|
||||
Return:
|
||||
A path to disk image to be used for testing
|
||||
"""
|
||||
image_path = u_boot_config.persistent_data_dir
|
||||
image_path = image_path + '/test_efi_secboot_intca.img'
|
||||
|
||||
try:
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/mnt_efi_secboot_intca'
|
||||
check_call('rm -rf {}'.format(mnt_point), shell=True)
|
||||
check_call('mkdir -p {}'.format(mnt_point), shell=True)
|
||||
image_path, mnt_point = fs_helper.setup_image(ubman, 0, 0xc,
|
||||
basename='test_efi_secboot_intca')
|
||||
|
||||
# Create signature database
|
||||
# PK
|
||||
|
@ -190,7 +186,7 @@ def efi_boot_env_intca(request, u_boot_config):
|
|||
|
||||
# TestRoot
|
||||
check_call('cp %s/test/py/tests/test_efi_secboot/openssl.cnf %s'
|
||||
% (u_boot_config.source_dir, mnt_point), shell=True)
|
||||
% (ubman.config.source_dir, mnt_point), shell=True)
|
||||
check_call('cd %s; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestRoot.key 2048; openssl req -extensions v3_ca -new -x509 -days 365 -key TestRoot.key -out TestRoot.crt -subj "/CN=TEST_root/"; touch index.txt; touch index.txt.attr'
|
||||
% mnt_point, shell=True)
|
||||
# TestSub
|
||||
|
@ -231,7 +227,7 @@ def efi_boot_env_intca(request, u_boot_config):
|
|||
# in SignedData
|
||||
|
||||
check_call('cp %s/lib/efi_loader/helloworld.efi %s' %
|
||||
(u_boot_config.build_dir, mnt_point), shell=True)
|
||||
(ubman.config.build_dir, mnt_point), shell=True)
|
||||
# signed by TestCert
|
||||
check_call('cd %s; %ssbsign --key TestCert.key --cert TestCert.crt --out helloworld.efi.signed_a helloworld.efi'
|
||||
% (mnt_point, SBSIGN_PATH), shell=True)
|
||||
|
@ -242,8 +238,9 @@ def efi_boot_env_intca(request, u_boot_config):
|
|||
check_call('cd %s; cat TestSub.crt TestRoot.crt > TestSubRoot.crt; %ssbsign --key TestCert.key --cert TestCert.crt --addcert TestSubRoot.crt --out helloworld.efi.signed_abc helloworld.efi'
|
||||
% (mnt_point, SBSIGN_PATH), shell=True)
|
||||
|
||||
check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'.format(mnt_point, image_path), shell=True)
|
||||
check_call('rm -rf {}'.format(mnt_point), shell=True)
|
||||
fsfile = fs_helper.mk_fs(ubman.config, 'vfat', 0x1000000,
|
||||
'test_efi_secboot_intca', mnt_point)
|
||||
check_call(f'dd if={fsfile} of={image_path} bs=1M seek=1', shell=True)
|
||||
|
||||
except CalledProcessError as e:
|
||||
pytest.skip('Setup failed: %s' % e.cmd)
|
||||
|
@ -251,4 +248,5 @@ def efi_boot_env_intca(request, u_boot_config):
|
|||
else:
|
||||
yield image_path
|
||||
finally:
|
||||
call('rm -f %s' % image_path, shell=True)
|
||||
call('rm -rf %s' % mnt_point, shell=True)
|
||||
call('rm -f %s %s' % (image_path, fsfile), shell=True)
|
||||
|
|
|
@ -2,13 +2,57 @@
|
|||
""" Unit test for UEFI menu-driven configuration
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import pytest
|
||||
import time
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_eficonfig')
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_bootmgr')
|
||||
def test_efi_eficonfig(ubman, efi_eficonfig_data):
|
||||
def test_efi_eficonfig(ubman):
|
||||
|
||||
def prepare_image(u_boot_config):
|
||||
"""Set up a file system to be used in UEFI "eficonfig" command
|
||||
tests. This creates a disk image with the following files:
|
||||
initrd-1.img
|
||||
initrd-2.img
|
||||
initrddump.efi
|
||||
|
||||
Args:
|
||||
u_boot_config -- U-Boot configuration.
|
||||
|
||||
Return:
|
||||
A path to disk image to be used for testing
|
||||
|
||||
"""
|
||||
try:
|
||||
image_path, mnt_point = fs_helper.setup_image(u_boot_config, 0,
|
||||
0xc,
|
||||
basename='test_eficonfig')
|
||||
|
||||
with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 1")
|
||||
|
||||
with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 2")
|
||||
|
||||
shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi',
|
||||
mnt_point + '/initrddump.efi')
|
||||
|
||||
fsfile = fs_helper.mk_fs(ubman.config, 'vfat', 0x100000,
|
||||
'test_eficonfig', mnt_point)
|
||||
check_call(f'dd if={fsfile} of={image_path} bs=1M seek=1', shell=True)
|
||||
|
||||
yield image_path
|
||||
except CalledProcessError as err:
|
||||
pytest.skip('Preparing test_eficonfig image failed')
|
||||
call('rm -f %s' % image_path, shell=True)
|
||||
finally:
|
||||
call('rm -rf %s' % mnt_point, shell=True)
|
||||
call('rm -f %s' % image_path, shell=True)
|
||||
|
||||
def send_user_input_and_wait(user_str, expect_str):
|
||||
time.sleep(0.1) # TODO: does not work correctly without sleep
|
||||
|
@ -57,12 +101,6 @@ def test_efi_eficonfig(ubman, efi_eficonfig_data):
|
|||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
efi__data -- Path to the disk image used for testing.
|
||||
Test disk image has following files.
|
||||
initrd-1.img
|
||||
initrd-2.img
|
||||
initrddump.efi
|
||||
|
||||
"""
|
||||
# This test passes for unknown reasons in the bowels of U-Boot. It needs to
|
||||
# be replaced with a unit test.
|
||||
|
@ -71,6 +109,7 @@ def test_efi_eficonfig(ubman, efi_eficonfig_data):
|
|||
# Restart the system to clean the previous state
|
||||
ubman.restart_uboot()
|
||||
|
||||
efi_eficonfig_data = prepare_image(ubman.config)
|
||||
with ubman.temporary_timeout(500):
|
||||
#
|
||||
# Test Case 1: Check the menu is displayed
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
"""Fixture for UEFI eficonfig test
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from subprocess import check_call
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def efi_eficonfig_data(u_boot_config):
|
||||
"""Set up a file system to be used in UEFI "eficonfig" command
|
||||
tests
|
||||
|
||||
Args:
|
||||
u_boot_config -- U-Boot configuration.
|
||||
|
||||
Return:
|
||||
A path to disk image to be used for testing
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_efi_eficonfig'
|
||||
image_path = u_boot_config.persistent_data_dir + '/efi_eficonfig.img'
|
||||
|
||||
shutil.rmtree(mnt_point, ignore_errors=True)
|
||||
os.mkdir(mnt_point, mode = 0o755)
|
||||
|
||||
with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 1")
|
||||
|
||||
with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file:
|
||||
file.write("initrd 2")
|
||||
|
||||
shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi',
|
||||
mnt_point + '/initrddump.efi')
|
||||
|
||||
check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}',
|
||||
shell=True)
|
||||
|
||||
return image_path
|
|
@ -27,36 +27,6 @@ def mkdir_cond(dirname):
|
|||
if not os.path.exists(dirname):
|
||||
os.mkdir(dirname)
|
||||
|
||||
def setup_image(ubman, devnum, part_type, img_size=20, second_part=False,
|
||||
basename='mmc'):
|
||||
"""Create a disk image with a single partition
|
||||
|
||||
Args:
|
||||
ubman (ConsoleBase): Console to use
|
||||
devnum (int): Device number to use, e.g. 1
|
||||
part_type (int): Partition type, e.g. 0xc for FAT32
|
||||
img_size (int): Image size in MiB
|
||||
second_part (bool): True to contain a small second partition
|
||||
basename (str): Base name to use in the filename, e.g. 'mmc'
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
str: Filename of MMC image
|
||||
str: Directory name of scratch directory
|
||||
"""
|
||||
fname = os.path.join(ubman.config.source_dir, f'{basename}{devnum}.img')
|
||||
mnt = os.path.join(ubman.config.persistent_data_dir, 'scratch')
|
||||
mkdir_cond(mnt)
|
||||
|
||||
spec = f'type={part_type:x}, size={img_size - 2}M, start=1M, bootable'
|
||||
if second_part:
|
||||
spec += '\ntype=c'
|
||||
|
||||
utils.run_and_log(ubman, f'qemu-img create {fname} 20M')
|
||||
utils.run_and_log(ubman, f'sfdisk {fname}',
|
||||
stdin=spec.encode('utf-8'))
|
||||
return fname, mnt
|
||||
|
||||
def copy_partition(ubman, fsfile, outname):
|
||||
"""Copy a partition into a disk iamge
|
||||
|
||||
|
@ -74,7 +44,7 @@ def setup_bootmenu_image(ubman):
|
|||
This is modelled on Armbian 22.08 Jammy
|
||||
"""
|
||||
mmc_dev = 4
|
||||
fname, mnt = setup_image(ubman, mmc_dev, 0x83)
|
||||
fname, mnt = fs_helper.setup_image(ubman, mmc_dev, 0x83)
|
||||
|
||||
script = '''# DO NOT EDIT THIS FILE
|
||||
#
|
||||
|
@ -190,7 +160,7 @@ booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
|
|||
def setup_bootflow_image(ubman):
|
||||
"""Create a 20MB disk image with a single FAT partition"""
|
||||
mmc_dev = 1
|
||||
fname, mnt = setup_image(ubman, mmc_dev, 0xc, second_part=True)
|
||||
fname, mnt = fs_helper.setup_image(ubman, mmc_dev, 0xc, second_part=True)
|
||||
|
||||
vmlinux = 'vmlinuz-5.3.7-301.fc31.armv7hl'
|
||||
initrd = 'initramfs-5.3.7-301.fc31.armv7hl.img'
|
||||
|
@ -556,8 +526,8 @@ def setup_efi_image(ubman):
|
|||
"""Create a 20MB disk image with an EFI app on it"""
|
||||
devnum = 1
|
||||
basename = 'flash'
|
||||
fname, mnt = setup_image(ubman, devnum, 0xc, second_part=True,
|
||||
basename=basename)
|
||||
fname, mnt = fs_helper.setup_image(ubman, devnum, 0xc, second_part=True,
|
||||
basename=basename)
|
||||
|
||||
efi_dir = os.path.join(mnt, 'EFI')
|
||||
mkdir_cond(efi_dir)
|
||||
|
|
40
test/py/tests/test_xxd.py
Normal file
40
test/py/tests/test_xxd.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
""" Unit test for xxd command
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from subprocess import call, check_call, CalledProcessError
|
||||
from tests import fs_helper
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_xxd')
|
||||
def test_xxd(ubman):
|
||||
""" Unit test for xxd
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
"""
|
||||
try:
|
||||
scratch_dir = ubman.config.persistent_data_dir + '/scratch'
|
||||
|
||||
check_call('mkdir -p %s' % scratch_dir, shell=True)
|
||||
|
||||
with open(scratch_dir + '/hello', 'w', encoding = 'ascii') as file:
|
||||
file.write('hello world\n\x00\x01\x02\x03\x04\x05')
|
||||
|
||||
xxd_data = fs_helper.mk_fs(ubman.config, 'vfat', 0x100000,
|
||||
'test_xxd', scratch_dir)
|
||||
response = ubman.run_command_list([ f'host bind 0 {xxd_data}',
|
||||
'xxd host 0 hello'])
|
||||
|
||||
assert '00000000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 01 02 03 hello world.....\r\r\n' + \
|
||||
'00000010: 04 05 ..' \
|
||||
in response
|
||||
except CalledProcessError as err:
|
||||
pytest.skip('Preparing test_xxd image failed')
|
||||
call('rm -f %s' % xxd_data, shell=True)
|
||||
return
|
||||
finally:
|
||||
call('rm -rf %s' % scratch_dir, shell=True)
|
||||
call('rm -f %s' % xxd_data, shell=True)
|
|
@ -1,36 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
"""Fixture for xxd command test
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from subprocess import check_call, CalledProcessError
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def xxd_data(u_boot_config):
|
||||
"""Set up a file system to be used in xxd tests
|
||||
|
||||
Args:
|
||||
u_boot_config -- U-Boot configuration.
|
||||
"""
|
||||
mnt_point = u_boot_config.persistent_data_dir + '/test_xxd'
|
||||
image_path = u_boot_config.persistent_data_dir + '/xxd.img'
|
||||
|
||||
try:
|
||||
os.mkdir(mnt_point, mode = 0o755)
|
||||
|
||||
with open(mnt_point + '/hello', 'w', encoding = 'ascii') as file:
|
||||
file.write('hello world\n\x00\x01\x02\x03\x04\x05')
|
||||
|
||||
check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}',
|
||||
shell=True)
|
||||
|
||||
yield image_path
|
||||
except CalledProcessError:
|
||||
pytest.skip('Setup failed')
|
||||
finally:
|
||||
shutil.rmtree(mnt_point)
|
||||
if os.path.exists(image_path):
|
||||
os.remove(image_path)
|
|
@ -1,23 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
""" Unit test for xxd command
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_xxd')
|
||||
def test_xxd(ubman, xxd_data):
|
||||
""" Unit test for xxd
|
||||
|
||||
Args:
|
||||
ubman -- U-Boot console
|
||||
xxd_data -- Path to the disk image used for testing.
|
||||
"""
|
||||
response = ubman.run_command_list([
|
||||
f'host bind 0 {xxd_data}',
|
||||
'xxd host 0 hello'])
|
||||
|
||||
assert '00000000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 01 02 03 hello world.....\r\r\n' + \
|
||||
'00000010: 04 05 ..' \
|
||||
in response
|
|
@ -92,7 +92,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|||
libconfuse-dev \
|
||||
libgit2-dev \
|
||||
libjson-glib-dev \
|
||||
libguestfs-tools \
|
||||
libgnutls28-dev \
|
||||
libgnutls30 \
|
||||
liblz4-tool \
|
||||
|
@ -106,7 +105,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|||
libtool \
|
||||
libudev-dev \
|
||||
libusb-1.0-0-dev \
|
||||
linux-image-generic \
|
||||
lzma-alone \
|
||||
lzop \
|
||||
mount \
|
||||
|
@ -143,9 +141,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|||
xxd \
|
||||
zip
|
||||
|
||||
# Make kernels readable for libguestfs tools to work correctly
|
||||
RUN chmod +r /boot/vmlinu*
|
||||
|
||||
# Build GRUB UEFI targets for ARM & RISC-V, 32-bit and 64-bit
|
||||
RUN git clone git://git.savannah.gnu.org/grub.git /tmp/grub && \
|
||||
cd /tmp/grub && \
|
||||
|
|
Loading…
Add table
Reference in a new issue