[PATCH] test: boot: Add test for bootmeth_rauc

Martin Schwan m.schwan at phytec.de
Wed Oct 8 08:57:30 CEST 2025


Add a simple unit test for testing the RAUC bootmethod. Provide only the
very basic tests for now, running a scan and list, to verify correct
detection of the RAUC bootmethod. More advanced boot tests of this
bootmethod can be added in a separate patch.

This requires another mmc image (mmc9) to contain the following
partitions:

1. boot A: contains a dummy boot.scr
2. root A: contains an empty root filesystem
3. boot B: contains a dummy boot.scr
4. root B: contains an empty root filesystem

The bootmeth_rauc scans all four partitions for existence and expects a
boot script in each boot partition.

Also add BOOTMETH_RAUC as a dependency on sandbox so that we can test
this with:

$ ./test/py/test.py -B sandbox --build -k test_ut # build the mmc9.img
$ ./test/py/test.py -B sandbox --build -k bootflow_rauc

Signed-off-by: Martin Schwan <m.schwan at phytec.de>
---
 arch/sandbox/dts/test.dts |  8 +++++++
 configs/sandbox_defconfig |  1 +
 test/boot/bootflow.c      | 57 +++++++++++++++++++++++++++++++++++++++++++++++
 test/py/tests/test_ut.py  | 45 +++++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index a2c739a2044c728a96b5f4acbf439a42d7e12fb5..25d1a8299c6462295edbe7bdade167c96ac7e9bf 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -46,6 +46,7 @@
 		mmc6 = "/mmc6";
 		mmc7 = "/mmc7";
 		mmc8 = "/mmc8";
+		mmc9 = "/mmc9";
 		pci0 = &pci0;
 		pci1 = &pci1;
 		pci2 = &pci2;
@@ -1230,6 +1231,13 @@
 		filename = "mmc8.img";
 	};
 
+	/* This is used for RAUC boot tests */
+	mmc9 {
+		status = "disabled";
+		compatible = "sandbox,mmc";
+		filename = "mmc9.img";
+	};
+
 	pch {
 		compatible = "sandbox,pch";
 	};
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 23651ec764dbc2d83be62cc0d91216eebd91acc5..b7a5d81bb71d9dd58ba20c33049d1b4534ea21f3 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -23,6 +23,7 @@ CONFIG_FIT_RSASSA_PSS=y
 CONFIG_FIT_CIPHER=y
 CONFIG_FIT_VERBOSE=y
 CONFIG_BOOTMETH_ANDROID=y
+CONFIG_BOOTMETH_RAUC=y
 CONFIG_UPL=y
 CONFIG_LEGACY_IMAGE_FORMAT=y
 CONFIG_MEASURED_BOOT=y
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 8de5a310add38798f3a52ea6cd796bdffdb16bd6..d3d1d410a6de349f880a4fb06cbc41804dc6a9a8 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -31,6 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
 
 extern U_BOOT_DRIVER(bootmeth_android);
 extern U_BOOT_DRIVER(bootmeth_cros);
+extern U_BOOT_DRIVER(bootmeth_rauc);
 extern U_BOOT_DRIVER(bootmeth_2script);
 
 /* Use this as the vendor for EFI to tell the app to exit boot services */
@@ -1332,6 +1333,62 @@ static int bootflow_efi(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE);
 
+/* Test RAUC bootmeth */
+static int bootflow_rauc(struct unit_test_state *uts)
+{
+	const char *mmc_dev = "mmc9";
+	struct bootstd_priv *std;
+	struct udevice *bootstd;
+	static const char *order[] = {NULL, NULL};
+	const char **old_order;
+	ofnode root;
+	ofnode node;
+
+	order[0] = mmc_dev;
+
+	if (!CONFIG_IS_ENABLED(BOOTMETH_RAUC))
+		return -EAGAIN;
+
+	/* Enable the requested mmc node since we need a different bootflow */
+	root = oftree_root(oftree_default());
+	node = ofnode_find_subnode(root, mmc_dev);
+	ut_assert(ofnode_valid(node));
+	ut_assertok(lists_bind_fdt(gd->dm_root, node, NULL, NULL, false));
+
+	/* Enable the rauc bootmeth */
+	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
+	ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_rauc),
+				"rauc", 0, ofnode_null(), NULL));
+
+	/* Change the device and bootmeth order */
+	std = dev_get_priv(bootstd);
+	old_order = std->bootdev_order;
+	std->bootdev_order = order;
+
+	ut_assertok(bootmeth_set_order("rauc"));
+
+	/* Run scan and list */
+	ut_assertok(run_command("bootflow scan", 0));
+	ut_assert_console_end();
+
+	ut_assertok(run_command("bootflow list", 0));
+
+	ut_assert_nextlinen("Showing all");
+	ut_assert_nextlinen("Seq");
+	ut_assert_nextlinen("---");
+	ut_assert_nextlinen("  0  rauc         ready   mmc          0  mmc9.bootdev.whole      ");
+	ut_assert_nextlinen("---");
+	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
+
+	ut_assert_console_end();
+
+	/* Restore the order used by the device tree */
+	std->bootdev_order = old_order;
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_rauc, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
+
 /* Check 'bootflow scan' provides a list of images */
 static int bootstd_images(struct unit_test_state *uts)
 {
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index cdf54adc6008c21d67eec466c3245c75208a2ec9..2e6b050ec2bafc765d1f7bb0c94a553b51ea69c2 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -547,6 +547,50 @@ def setup_efi_image(ubman):
     utils.run_and_log(ubman, f'rm -rf {mnt}')
     utils.run_and_log(ubman, f'rm -f {fsfile}')
 
+def setup_rauc_image(ubman):
+    """Create a 40MB disk image with an A/B RAUC system on it"""
+    mmc_dev = 9
+    fname = os.path.join(ubman.config.source_dir, f'mmc{mmc_dev}.img')
+    mnt = os.path.join(ubman.config.persistent_data_dir, 'scratch')
+
+    spec = 'type=c, size=8M, start=1M, bootable\n' \
+           'type=c, size=10M\n' \
+           'type=c, size=8M, bootable\n' \
+           'type=c, size=10M'
+
+    utils.run_and_log(ubman, f'qemu-img create {fname} 40M')
+    utils.run_and_log(ubman, ['sh', '-c', f'printf "{spec}" | sfdisk {fname}'])
+
+    # Generate boot script
+    script = '# dummy boot script'
+    bootdir = os.path.join(mnt, 'boot')
+    utils.run_and_log(ubman, f'mkdir -p {bootdir}')
+    cmd_fname = os.path.join(bootdir, 'boot.cmd')
+    scr_fname = os.path.join(bootdir, 'boot.scr')
+    with open(cmd_fname, 'w', encoding='ascii') as outf:
+        print(script, file=outf)
+
+    mkimage = os.path.join(ubman.config.build_dir, 'tools/mkimage')
+    utils.run_and_log(
+        ubman, f'{mkimage} -C none -A arm -T script -d {cmd_fname} {scr_fname}')
+
+    # Create boot filesystem image with boot script in it and copy to disk image
+    fsfile = 'rauc_boot.img'
+    utils.run_and_log(ubman, f'fallocate -l 8M {fsfile}')
+    utils.run_and_log(ubman, f'mkfs.vfat {fsfile}')
+    utils.run_and_log(ubman, ['sh', '-c', f'mcopy -vs -i {fsfile} {scr_fname} ::/'])
+    utils.run_and_log(ubman, f'dd if={fsfile} of=mmc{mmc_dev}.img bs=1M seek=1 conv=notrunc')
+    utils.run_and_log(ubman, f'dd if={fsfile} of=mmc{mmc_dev}.img bs=1M seek=19 conv=notrunc')
+    utils.run_and_log(ubman, f'rm -f {fsfile} {cmd_fname} {scr_fname}')
+
+    # Create empty root filesystem image and copy to disk image
+    fsfile = 'rauc_root.img'
+    utils.run_and_log(ubman, f'fallocate -l 10M {fsfile}')
+    utils.run_and_log(ubman, f'mkfs.vfat {fsfile}')
+    utils.run_and_log(ubman, f'dd if={fsfile} of=mmc{mmc_dev}.img bs=1M seek=9 conv=notrunc')
+    utils.run_and_log(ubman, f'dd if={fsfile} of=mmc{mmc_dev}.img bs=1M seek=27 conv=notrunc')
+    utils.run_and_log(ubman, f'rm -f {fsfile}')
+
 @pytest.mark.buildconfigspec('cmd_bootflow')
 @pytest.mark.buildconfigspec('sandbox')
 def test_ut_dm_init_bootstd(ubman):
@@ -558,6 +602,7 @@ def test_ut_dm_init_bootstd(ubman):
     setup_cros_image(ubman)
     setup_android_image(ubman)
     setup_efi_image(ubman)
+    setup_rauc_image(ubman)
 
     # Restart so that the new mmc1.img is picked up
     ubman.restart_uboot()

---
base-commit: dc6c80056e21a27e28e1be62ac724302ef526841
change-id: 20251006-wip-bootmeth-rauc-tests-a8ed5deb7486

Best regards,
-- 
Martin Schwan <m.schwan at phytec.de>



More information about the U-Boot mailing list