test: Add a test for FIT image printing

The code for printing FITs is quite messy, with lots of separate
printf() calls, an indentation string, etc.

It also has no tests.

In preparation for refactoring this code, add a test. Use Python code
to create the test image and C code to test it.

The test covers FIT description, image details (type, architecture, OS,
addresses), and configuration details.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
Simon Glass
2025-11-17 15:56:46 -07:00
parent cca21f0d2f
commit 4bbf198c46
3 changed files with 214 additions and 0 deletions

View File

@@ -5,6 +5,7 @@
ifdef CONFIG_UT_BOOTSTD
obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o
obj-$(CONFIG_FIT) += image.o
obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o
obj-$(CONFIG_BLK_LUKS) += luks.o
obj-$(CONFIG_EXPO) += expo.o expo_common.o

93
test/boot/fit_print.c Normal file
View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Test for FIT image printing
*
* Copyright 2025 Canonical Ltd
* Written by Simon Glass <simon.glass@canonical.com>
*/
#include <image.h>
#include <mapmem.h>
#include <os.h>
#include <test/ut.h>
#include <linux/libfdt.h>
#include "bootstd_common.h"
/* Test fit_print_contents() output */
static int test_fit_print_norun(struct unit_test_state *uts)
{
char fname[256];
void *fit;
void *buf;
ulong addr;
int size;
/* Load the FIT created by the Python test */
ut_assertok(os_persistent_file(fname, sizeof(fname), "test-fit.fit"));
ut_assertok(os_read_file(fname, &buf, &size));
/* Copy to address 0x10000 and print from there */
addr = 0x10000;
fit = map_sysmem(addr, size);
memcpy(fit, buf, size);
/* Print it and check output line by line */
console_record_reset_enable();
fit_print_contents(fit);
/* Check every line of output */
ut_assert_nextline(" FIT description: Test FIT image for printing");
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
ut_assert_nextline(" Image 0 (kernel)");
ut_assert_nextline(" Description: Test kernel");
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
ut_assert_nextline(" Type: Kernel Image");
ut_assert_nextline(" Compression: gzip compressed");
ut_assert_nextline(" Data Start: 0x000100c4");
ut_assert_nextline(" Data Size: 327 Bytes = 327 Bytes");
ut_assert_nextline(" Architecture: Sandbox");
ut_assert_nextline(" OS: Linux");
ut_assert_nextline(" Load Address: 0x01000000");
ut_assert_nextline(" Entry Point: 0x01000000");
ut_assert_nextline(" Hash algo: sha256");
ut_assert_nextline(" Hash value: fad998b94ef12fdac0c347915d8b9b6069a4011399e1a2097638a2cb33244cee");
ut_assert_nextline(" Image 1 (ramdisk)");
ut_assert_nextline(" Description: Test ramdisk");
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
ut_assert_nextline(" Type: RAMDisk Image");
ut_assert_nextline(" Compression: uncompressed");
ut_assert_nextline(" Data Start: 0x00010304");
ut_assert_nextline(" Data Size: 301 Bytes = 301 Bytes");
ut_assert_nextline(" Architecture: Sandbox");
ut_assert_nextline(" OS: Linux");
ut_assert_nextline(" Load Address: 0x02000000");
ut_assert_nextline(" Entry Point: unavailable");
ut_assert_nextline(" Hash algo: sha256");
ut_assert_nextline(" Hash value: 53e2a65d92ad890dcd89d83a1f95ad6b8206e0e4889548b035062fc494e7f655");
ut_assert_nextline(" Image 2 (fdt)");
ut_assert_nextline(" Description: Test FDT");
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
ut_assert_nextline(" Type: Flat Device Tree");
ut_assert_nextline(" Compression: uncompressed");
ut_assert_nextline(" Data Start: 0x00010514");
ut_assert_nextline(" Data Size: 157 Bytes = 157 Bytes");
ut_assert_nextline(" Architecture: Sandbox");
ut_assert_nextline(" Hash algo: sha256");
ut_assert_nextline(" Hash value: 51918524b06745cae06331047c7e566909431bf71338e5f703dffba1823274f4");
ut_assert_nextline(" Default Configuration: 'conf-1'");
ut_assert_nextline(" Configuration 0 (conf-1)");
ut_assert_nextline(" Description: Test configuration");
ut_assert_nextline(" Kernel: kernel");
ut_assert_nextline(" Init Ramdisk: ramdisk");
ut_assert_nextline(" FDT: fdt");
ut_assert_nextline(" Configuration 1 (conf-2)");
ut_assert_nextline(" Description: Alternate configuration");
ut_assert_nextline(" Kernel: kernel");
ut_assert_nextline(" FDT: fdt");
ut_assert_console_end();
os_free(buf);
return 0;
}
BOOTSTD_TEST(test_fit_print_norun, UTF_CONSOLE | UTF_MANUAL);

View File

@@ -0,0 +1,120 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright 2025 Canonical Ltd
# Written by Simon Glass <simon.glass@canonical.com>
"""Test for FIT image printing"""
import os
import pytest
import fit_util
import utils
# ITS for testing FIT printing with hashes, ramdisk, and multiple configs
PRINT_ITS = '''
/dts-v1/;
/ {
description = "Test FIT image for printing";
#address-cells = <1>;
images {
kernel {
description = "Test kernel";
data = /incbin/("%(kernel)s");
type = "kernel";
arch = "sandbox";
os = "linux";
compression = "gzip";
load = <0x1000000>;
entry = <0x1000000>;
hash-1 {
algo = "sha256";
};
};
ramdisk {
description = "Test ramdisk";
data = /incbin/("%(ramdisk)s");
type = "ramdisk";
arch = "sandbox";
os = "linux";
compression = "none";
load = <0x2000000>;
hash-1 {
algo = "sha256";
};
};
fdt {
description = "Test FDT";
data = /incbin/("%(fdt)s");
type = "flat_dt";
arch = "sandbox";
compression = "none";
hash-1 {
algo = "sha256";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Test configuration";
kernel = "kernel";
fdt = "fdt";
ramdisk = "ramdisk";
};
conf-2 {
description = "Alternate configuration";
kernel = "kernel";
fdt = "fdt";
};
};
};
'''
@pytest.mark.boardspec('sandbox')
@pytest.mark.buildconfigspec('fit_print')
@pytest.mark.requiredtool('dtc')
def test_fit_print(ubman):
"""Test fit_print_contents() via C unit test"""
mkimage = os.path.join(ubman.config.build_dir, 'tools/mkimage')
# Create test files (make kernel ~6.3K)
kernel = fit_util.make_kernel(ubman, 'test-kernel.bin',
'kernel with some extra test data')
# Compress the kernel (with -n to avoid timestamps for reproducibility)
kernel_gz = kernel + '.gz'
utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', kernel])
fdt = fit_util.make_dtb(ubman, '''
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <0>;
model = "Test";
};
''', 'test-fdt')
ramdisk = fit_util.make_kernel(ubman, 'test-ramdisk.bin', 'ramdisk')
# Compress the ramdisk (with -n to avoid timestamps for reproducibility)
ramdisk_gz = ramdisk + '.gz'
utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', ramdisk])
# Create FIT image with fixed timestamp for reproducible output
params = {
'kernel': kernel_gz,
'fdt': fdt,
'ramdisk': ramdisk_gz,
}
env = os.environ.copy()
env['SOURCE_DATE_EPOCH'] = '1234567890' # 2009-02-13 23:31:30 UTC
fit = os.path.join(ubman.config.persistent_data_dir, 'test-fit.fit')
its = fit_util.make_its(ubman, PRINT_ITS, params)
utils.run_and_log(ubman, [mkimage, '-f', its, fit], env=env)
# Run the C test which will load and verify this FIT
ubman.run_command('ut -f bootstd test_fit_print_norun')
result = ubman.run_command('echo $?')
assert '0' == result