oe-selftest: fitimage: test absent optional nodes in ITS files

Extend the test framework to verify that certain optional nodes are properly
absent from ITS files based on configuration. The _get_req_its_paths()
method now returns a tuple containing both expected and not-expected
paths, enabling negative testing of conditional components.

Test improvements:
- Add verification for absent bootscr, setup, and ramdisk image nodes
  when their respective features are disabled
- Extend configuration node testing with proper kernel/fdt/ramdisk
  field validation based on device tree and initramfs settings

Code cleanup:
- Remove unused tempfile module import
- Sort bb_vars keys alphabetically in _test_fitimage_py()
- Add debug output for bb_vars overrides when debug logging is enabled
- Remove trailing empty line
- Fix DTB file ordering for consistent test results

(From OE-Core rev: 90dbdacc7f22120b4a96aad2a89b363fdd944079)

Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Adrian Freihofer 2025-10-27 21:56:49 +01:00 committed by Richard Purdie
parent 3fb242e5fe
commit 6674e5bebe

View File

@ -9,7 +9,6 @@ import re
import shlex
import logging
import pprint
import tempfile
import oe.fitimage
@ -47,10 +46,11 @@ class FitImageTestCase(OESelftestTestCase):
# Check if the its file contains the expected paths and attributes.
# The _get_req_* functions are implemented by more specific chield classes.
self._check_its_file()
req_its_paths = self._get_req_its_paths()
req_its_paths, not_req_its_paths = self._get_req_its_paths()
req_sigvalues_config = self._get_req_sigvalues_config()
req_sigvalues_image = self._get_req_sigvalues_image()
# Compare the its file against req_its_paths, req_sigvalues_config, req_sigvalues_image
# Compare the its file against req_its_paths, not_req_its_paths,
# req_sigvalues_config, req_sigvalues_image
# Call the dumpimage utiliy and check that it prints all the expected paths and attributes
# The _get_req_* functions are implemented by more specific chield classes.
@ -198,7 +198,7 @@ class FitImageTestCase(OESelftestTestCase):
# Support only the test recipe which provides 1 devicetree and 1 devicetree overlay
pref_prov_dtb = bb_vars.get('PREFERRED_PROVIDER_virtual/dtb')
if pref_prov_dtb == "bbb-dtbs-as-ext":
all_dtbs += ["am335x-bonegreen-ext.dtb", "BBORG_RELAY-00A2.dtbo"]
all_dtbs += ["BBORG_RELAY-00A2.dtbo", "am335x-bonegreen-ext.dtb"]
dtb_symlinks.append("am335x-bonegreen-ext-alias.dtb")
return (all_dtbs, dtb_symlinks)
@ -234,8 +234,9 @@ class FitImageTestCase(OESelftestTestCase):
self.logger.debug("its file: %s" % its_file.read())
# Generate a list of expected paths in the its file
req_its_paths = self._get_req_its_paths(bb_vars)
req_its_paths, not_req_its_paths = self._get_req_its_paths(bb_vars)
self.logger.debug("req_its_paths:\n%s\n" % pprint.pformat(req_its_paths, indent=4))
self.logger.debug("not_req_its_paths:\n%s\n" % pprint.pformat(not_req_its_paths, indent=4))
# Generate a dict of expected configuration signature nodes
req_sigvalues_config = self._get_req_sigvalues_config(bb_vars)
@ -275,6 +276,11 @@ class FitImageTestCase(OESelftestTestCase):
if not req_path in its_paths:
self.fail('Missing path in its file: %s (%s)' % (req_path, its_file_path))
# check if all not expected paths are absent in the its file
for not_req_path in not_req_its_paths:
if not_req_path in its_paths:
self.fail('Unexpected path found in its file: %s (%s)' % (not_req_path, its_file_path))
# Check if all the expected singnature nodes (images and configurations) are found
self.logger.debug("sigs:\n%s\n" % pprint.pformat(sigs, indent=4))
if req_sigvalues_config or req_sigvalues_image:
@ -353,7 +359,7 @@ class FitImageTestCase(OESelftestTestCase):
def _get_req_its_paths(self, bb_vars):
self.logger.error("This function needs to be implemented")
return []
return ([], [])
def _get_req_its_fields(self, bb_vars):
self.logger.error("This function needs to be implemented")
@ -499,7 +505,7 @@ class KernelFitImageBase(FitImageTestCase):
return (fitimage_its_path, fitimage_path)
def _get_req_its_paths(self, bb_vars):
"""Generate a list of expected paths in the its file
"""Generate a list of expected and a list of not expected paths in the its file
Example:
[
@ -515,15 +521,26 @@ class KernelFitImageBase(FitImageTestCase):
uboot_sign_enable = bb_vars.get('UBOOT_SIGN_ENABLE')
# image nodes
images = [ 'kernel-1' ]
images = ['kernel-1']
not_images = []
if dtb_files:
images += [ 'fdt-' + dtb for dtb in dtb_files ]
if fit_uboot_env:
images.append('bootscr-' + fit_uboot_env)
else:
not_images.append('bootscr-boot.cmd')
if bb_vars['MACHINE'] == "qemux86-64": # Not really the right if
images.append('setup-1')
else:
not_images.append('setup-1')
if initramfs_image and initramfs_image_bundle != "1":
images.append('ramdisk-1')
else:
not_images.append('ramdisk-1')
# configuration nodes (one per DTB and also one per symlink)
if dtb_files:
@ -541,7 +558,12 @@ class KernelFitImageBase(FitImageTestCase):
req_its_paths.append(['/', 'configurations', configuration, 'hash-1'])
if uboot_sign_enable == "1":
req_its_paths.append(['/', 'configurations', configuration, 'signature-1'])
return req_its_paths
not_req_its_paths = []
for image in not_images:
not_req_its_paths.append(['/', 'images', image])
return (req_its_paths, not_req_its_paths)
def _get_req_its_fields(self, bb_vars):
initramfs_image = bb_vars['INITRAMFS_IMAGE']
@ -572,10 +594,23 @@ class KernelFitImageBase(FitImageTestCase):
fit_conf_prefix = bb_vars.get('FIT_CONF_PREFIX', "conf-")
its_field_check.append('default = "' + fit_conf_prefix + fit_conf_default_dtb + '";')
its_field_check.append('kernel = "kernel-1";')
# configuration nodes (one per DTB and also one per symlink)
dtb_files, dtb_symlinks = FitImageTestCase._get_dtb_files(bb_vars)
if dtb_files:
for dtb in dtb_files:
its_field_check.append('kernel = "kernel-1";')
its_field_check.append('fdt = "fdt-%s";' % dtb)
for dtb in dtb_symlinks:
its_field_check.append('kernel = "kernel-1";')
# Works only for tests were the symlink is with -alias suffix
its_field_check.append('fdt = "fdt-%s";' % dtb.replace('-alias', ''))
if initramfs_image and initramfs_image_bundle != "1":
its_field_check.append('ramdisk = "ramdisk-1";')
if initramfs_image and initramfs_image_bundle != "1":
its_field_check.append('ramdisk = "ramdisk-1";')
else:
its_field_check.append('kernel = "kernel-1";')
if initramfs_image and initramfs_image_bundle != "1":
its_field_check.append('ramdisk = "ramdisk-1";')
return its_field_check
@ -1032,20 +1067,21 @@ class FitImagePyTests(KernelFitImageBase):
# Provide variables without calling bitbake
bb_vars = {
# image-fitimage.conf
'FIT_ADDRESS_CELLS': "1",
'FIT_CONF_DEFAULT_DTB': "",
'FIT_CONF_PREFIX': "conf-",
'FIT_DESC': "Kernel fitImage for a dummy distro",
'FIT_HASH_ALG': "sha256",
'FIT_SIGN_ALG': "rsa2048",
'FIT_PAD_ALG': "pkcs-1.5",
'FIT_GENERATE_KEYS': "0",
'FIT_SIGN_NUMBITS': "2048",
'FIT_HASH_ALG': "sha256",
'FIT_KEY_GENRSA_ARGS': "-F4",
'FIT_KEY_REQ_ARGS': "-batch -new",
'FIT_KEY_SIGN_PKCS': "-x509",
'FIT_LINUX_BIN': "linux.bin",
'FIT_PAD_ALG': "pkcs-1.5",
'FIT_SIGN_ALG': "rsa2048",
'FIT_SIGN_INDIVIDUAL': "0",
'FIT_CONF_PREFIX': "conf-",
'FIT_SIGN_NUMBITS': "2048",
'FIT_SUPPORTED_INITRAMFS_FSTYPES': "cpio.lz4 cpio.lzo cpio.lzma cpio.xz cpio.zst cpio.gz ext2.gz cpio",
'FIT_CONF_DEFAULT_DTB': "",
'FIT_ADDRESS_CELLS': "1",
'FIT_UBOOT_ENV': "",
# kernel.bbclass
'UBOOT_ENTRYPOINT': "0x20008000",
@ -1072,6 +1108,9 @@ class FitImagePyTests(KernelFitImageBase):
}
if bb_vars_overrides:
bb_vars.update(bb_vars_overrides)
if logging.DEBUG >= self.logger.level:
debug_output = "\n".join([f"{key} = {value}" for key, value in bb_vars_overrides.items()])
self.logger.debug("bb_vars overrides:\n%s" % debug_output)
root_node = oe.fitimage.ItsNodeRootKernel(
bb_vars["FIT_DESC"], bb_vars["FIT_ADDRESS_CELLS"],
@ -1204,7 +1243,7 @@ class UBootFitImageTests(FitImageTestCase):
req_its_paths.append(['/', 'images', image, 'signature'])
for configuration in configurations:
req_its_paths.append(['/', 'configurations', configuration])
return req_its_paths
return (req_its_paths, [])
def _get_req_its_fields(self, bb_vars):
loadables = ["uboot"]
@ -1730,4 +1769,3 @@ UBOOT_FIT_GENERATE_KEYS = "1"
self.write_config(config)
bb_vars = self._fit_get_bb_vars()
self._test_fitimage(bb_vars)