From 47ceaf8816aa1eb1d8a924b3d31c93a852de029d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:22 -0600 Subject: [PATCH 01/10] test/py: Rework test_cat to not use virt-make-fs The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. Signed-off-by: Tom Rini --- test/py/tests/test_cat.py | 37 ++++++++++++++++++++++++++++++ test/py/tests/test_cat/conftest.py | 36 ----------------------------- test/py/tests/test_cat/test_cat.py | 20 ---------------- 3 files changed, 37 insertions(+), 56 deletions(-) create mode 100644 test/py/tests/test_cat.py delete mode 100644 test/py/tests/test_cat/conftest.py delete mode 100644 test/py/tests/test_cat/test_cat.py diff --git a/test/py/tests/test_cat.py b/test/py/tests/test_cat.py new file mode 100644 index 00000000000..252c3d50a02 --- /dev/null +++ b/test/py/tests/test_cat.py @@ -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) diff --git a/test/py/tests/test_cat/conftest.py b/test/py/tests/test_cat/conftest.py deleted file mode 100644 index 320e7ebd295..00000000000 --- a/test/py/tests/test_cat/conftest.py +++ /dev/null @@ -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) diff --git a/test/py/tests/test_cat/test_cat.py b/test/py/tests/test_cat/test_cat.py deleted file mode 100644 index 883803fece7..00000000000 --- a/test/py/tests/test_cat/test_cat.py +++ /dev/null @@ -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 From f98d2a31271dd3357e4f13a77b62cd383bd3f09d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:23 -0600 Subject: [PATCH 02/10] test/py: Rework test_xxd to not use virt-make-fs The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. Signed-off-by: Tom Rini --- test/py/tests/test_xxd.py | 40 ++++++++++++++++++++++++++++++ test/py/tests/test_xxd/conftest.py | 36 --------------------------- test/py/tests/test_xxd/test_xxd.py | 23 ----------------- 3 files changed, 40 insertions(+), 59 deletions(-) create mode 100644 test/py/tests/test_xxd.py delete mode 100644 test/py/tests/test_xxd/conftest.py delete mode 100644 test/py/tests/test_xxd/test_xxd.py diff --git a/test/py/tests/test_xxd.py b/test/py/tests/test_xxd.py new file mode 100644 index 00000000000..c457c54146c --- /dev/null +++ b/test/py/tests/test_xxd.py @@ -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) diff --git a/test/py/tests/test_xxd/conftest.py b/test/py/tests/test_xxd/conftest.py deleted file mode 100644 index 47c7cce1aa9..00000000000 --- a/test/py/tests/test_xxd/conftest.py +++ /dev/null @@ -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) diff --git a/test/py/tests/test_xxd/test_xxd.py b/test/py/tests/test_xxd/test_xxd.py deleted file mode 100644 index c04bf8b7a25..00000000000 --- a/test/py/tests/test_xxd/test_xxd.py +++ /dev/null @@ -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 From fce92e304fcd8bdba522a43aeef12cc3b0b2df56 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:24 -0600 Subject: [PATCH 03/10] test/py/tests: Move "setup_image" from test_ut.py to fs_helper.py The generic function in test_ut.py to create a disk image with partition table can be useful outside of test_ut.py so move it to be available more clearly. To make this a bit more easily used library function, make use of check_call directly rather than calling things though u_boot_utils. In turn, to more easily handle stdin here, use the shell "printf" utility to pass sfdisk the specification to create as we do not have an actual file descriptor to use here. Signed-off-by: Tom Rini --- test/py/tests/fs_helper.py | 34 ++++++++++++++++++++++++++++++++++ test/py/tests/test_ut.py | 38 ++++---------------------------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index ccfc0201a49..f3e81b6bc61 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -69,6 +69,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} 20M', 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 diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index ea0c43cd4fc..3a3f12d0898 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -27,43 +27,13 @@ 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 setup_bootmenu_image(ubman): """Create a 20MB disk image with a single ext4 partition 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 # @@ -179,7 +149,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' @@ -545,8 +515,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) From 2c092875abfd9269a34b3cc03930066fda53a476 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:25 -0600 Subject: [PATCH 04/10] test/py: Fix a problem with setup_image While we can be passed an image size to use, we always called qemu-img with 20M as the size. Fix this by using the size parameter. Signed-off-by: Tom Rini --- test/py/tests/fs_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index f3e81b6bc61..2faab21509f 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -95,7 +95,7 @@ def setup_image(ubman, devnum, part_type, img_size=20, second_part=False, try: check_call(f'mkdir -p {mnt}', shell=True) - check_call(f'qemu-img create {fname} 20M', 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) From 4b33810511445dfd5466223f8fad2961b0732abe Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:26 -0600 Subject: [PATCH 05/10] test/py: Rework test_efi_bootmgr to not use virt-make-fs The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. Signed-off-by: Tom Rini --- test/py/tests/test_efi_bootmgr.py | 70 +++++++++++++++++++ test/py/tests/test_efi_bootmgr/conftest.py | 38 ---------- .../test_efi_bootmgr/test_efi_bootmgr.py | 44 ------------ 3 files changed, 70 insertions(+), 82 deletions(-) create mode 100644 test/py/tests/test_efi_bootmgr.py delete mode 100644 test/py/tests/test_efi_bootmgr/conftest.py delete mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py diff --git a/test/py/tests/test_efi_bootmgr.py b/test/py/tests/test_efi_bootmgr.py new file mode 100644 index 00000000000..4c10cbdf17d --- /dev/null +++ b/test/py/tests/test_efi_bootmgr.py @@ -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) diff --git a/test/py/tests/test_efi_bootmgr/conftest.py b/test/py/tests/test_efi_bootmgr/conftest.py deleted file mode 100644 index 0eca025058e..00000000000 --- a/test/py/tests/test_efi_bootmgr/conftest.py +++ /dev/null @@ -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 diff --git a/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py b/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py deleted file mode 100644 index 8800e9de5b4..00000000000 --- a/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py +++ /dev/null @@ -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') From 397fc80b9fc2c6831beaaf92d66d725ca33837e6 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:27 -0600 Subject: [PATCH 06/10] test/py: Rework test_eficonfig to not use virt-make-fs The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. As this test already had a number of internal functions, add a prepare_image function to do this part of the test. Acked-by: Ilias Apalodimas Signed-off-by: Tom Rini --- .../{test_eficonfig => }/test_eficonfig.py | 53 ++++++++++++++++--- test/py/tests/test_eficonfig/conftest.py | 40 -------------- 2 files changed, 46 insertions(+), 47 deletions(-) rename test/py/tests/{test_eficonfig => }/test_eficonfig.py (88%) delete mode 100644 test/py/tests/test_eficonfig/conftest.py diff --git a/test/py/tests/test_eficonfig/test_eficonfig.py b/test/py/tests/test_eficonfig.py similarity index 88% rename from test/py/tests/test_eficonfig/test_eficonfig.py rename to test/py/tests/test_eficonfig.py index 3ca8e27c76b..ac1600ec252 100644 --- a/test/py/tests/test_eficonfig/test_eficonfig.py +++ b/test/py/tests/test_eficonfig.py @@ -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 diff --git a/test/py/tests/test_eficonfig/conftest.py b/test/py/tests/test_eficonfig/conftest.py deleted file mode 100644 index 0a82fbefd75..00000000000 --- a/test/py/tests/test_eficonfig/conftest.py +++ /dev/null @@ -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 From 27cca9e5d3a09d234db1a289cc1d19aec71b6910 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:28 -0600 Subject: [PATCH 07/10] test/py: Rework test_efi_capsule to not use virt-make-fs FIXME: Reword more The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. The main change here is that our mount point directory has changed from "test_efi_capsule" to "scratch" and so we need to update other functions too. As the disk image that we get created doesn't have a GPT, invoke sgdisk to do a conversion first. Signed-off-by: Tom Rini --- .../tests/test_efi_capsule/capsule_common.py | 2 +- test/py/tests/test_efi_capsule/conftest.py | 45 ++++++++++--------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/test/py/tests/test_efi_capsule/capsule_common.py b/test/py/tests/test_efi_capsule/capsule_common.py index 40b3fca809e..04dabc176c4 100644 --- a/test/py/tests/test_efi_capsule/capsule_common.py +++ b/test/py/tests/test_efi_capsule/capsule_common.py @@ -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() diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 61eab5112a1..961d2e0b3c1 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -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) From 7bf75f3e36d0907e83c84ed252c8f24b1659985c Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:29 -0600 Subject: [PATCH 08/10] test/py: Rework test_efi_secboot to not use virt-make-fs The problem with using "virt-make-fs" to make a filesystem image is that it is extremely slow. Switch to using the fs_helper functions we have instead from the filesystem tests as these can add files to images and are significantly faster and still do not require root access. Signed-off-by: Tom Rini --- test/py/tests/test_efi_secboot/conftest.py | 52 +++++++++++----------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index 0fa0747fc76..aa9a3536296 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -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) From 6df302c17881d47abaceefb9a13c5723c15110c3 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:30 -0600 Subject: [PATCH 09/10] doc/develop/py_testing.rst: Update section on filesystem images Now that we have no users of "virt-make-fs" nor users of "sudo" for creating disk images update the documentation. We remove packages that are no longer required (and related text) as well as be firm in our wording around not using "sudo". Signed-off-by: Tom Rini --- doc/develop/py_testing.rst | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/doc/develop/py_testing.rst b/doc/develop/py_testing.rst index 40a85380343..502053f09fc 100644 --- a/doc/develop/py_testing.rst +++ b/doc/develop/py_testing.rst @@ -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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From eb1b90ec57a43ff4799d9626a1481acd01a4adb4 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 20 Mar 2025 07:59:31 -0600 Subject: [PATCH 10/10] Dockerfile: Update to drop virt-make-fs packages Now that we do not need nor want people to use virt-make-fs for filesystem tests, remove the related packages from the installation list. Signed-off-by: Tom Rini --- tools/docker/Dockerfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 569912303fc..f28fbf97cac 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -91,7 +91,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 \ @@ -105,7 +104,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 \ @@ -142,9 +140,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 && \