From 44b3aadffaaf26ec9c404dae8b6a8f231870fc63 Mon Sep 17 00:00:00 2001 From: Julien Olivain Date: Sun, 5 Mar 2023 18:30:55 +0100 Subject: [PATCH] support/testing/tests/package/test_ddrescue.py: new runtime test Signed-off-by: Julien Olivain Signed-off-by: Thomas Petazzoni --- DEVELOPERS | 2 + .../testing/tests/package/test_ddrescue.py | 94 +++++++++++++++++++ .../test_ddrescue/linux-ddrescue.fragment | 4 + 3 files changed, 100 insertions(+) create mode 100644 support/testing/tests/package/test_ddrescue.py create mode 100644 support/testing/tests/package/test_ddrescue/linux-ddrescue.fragment diff --git a/DEVELOPERS b/DEVELOPERS index 9aa26418b5..6c3498484f 100644 --- a/DEVELOPERS +++ b/DEVELOPERS @@ -1729,6 +1729,8 @@ F: support/testing/tests/package/sample_python_distro.py F: support/testing/tests/package/sample_python_gnupg.py F: support/testing/tests/package/sample_python_pyalsa.py F: support/testing/tests/package/sample_python_spake2.py +F: support/testing/tests/package/test_ddrescue.py +F: support/testing/tests/package/test_ddrescue/ F: support/testing/tests/package/test_gnupg2.py F: support/testing/tests/package/test_highway.py F: support/testing/tests/package/test_hwloc.py diff --git a/support/testing/tests/package/test_ddrescue.py b/support/testing/tests/package/test_ddrescue.py new file mode 100644 index 0000000000..2206971421 --- /dev/null +++ b/support/testing/tests/package/test_ddrescue.py @@ -0,0 +1,94 @@ +import os + +import infra.basetest + + +class TestDdrescue(infra.basetest.BRTest): + + # A specific configuration is needed for testing ddrescue: + # - A kernel config fragment enables loop blk dev and device + # mapper dm-dust, which are used to simulate a failing storage + # block device. + # - dmraid user space package is needed to configure dm-dust + config = \ + """ + BR2_aarch64=y + BR2_TOOLCHAIN_EXTERNAL=y + BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0" + BR2_LINUX_KERNEL=y + BR2_LINUX_KERNEL_CUSTOM_VERSION=y + BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.15" + BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y + BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config" + BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{}" + BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y + BR2_PACKAGE_DDRESCUE=y + BR2_PACKAGE_DMRAID=y + BR2_TARGET_ROOTFS_CPIO=y + BR2_TARGET_ROOTFS_CPIO_GZIP=y + # BR2_TARGET_ROOTFS_TAR is not set + """.format( + infra.filepath("tests/package/test_ddrescue/linux-ddrescue.fragment") + ) + + def test_run(self): + img = os.path.join(self.builddir, "images", "rootfs.cpio.gz") + kern = os.path.join(self.builddir, "images", "Image") + self.emulator.boot(arch="aarch64", + kernel=kern, + kernel_cmdline=["console=ttyAMA0"], + options=["-M", "virt", "-cpu", "cortex-a57", "-m", "256M", "-initrd", img]) + self.emulator.login() + + # Test variables: + dev_img = "/tmp/dev.img" + lo_dev = "/dev/loop0" + dm_dev_name = "dust0" + dm_dev = f"/dev/mapper/{dm_dev_name}" + ddrescue_img = "/tmp/ddrescue.img" + + # Test the program can execute + self.assertRunOk("ddrescue --version") + + # Create a 1MB file of zeroes for initial loopback block device + self.assertRunOk(f"dd if=/dev/zero of={dev_img} bs=1M count=1") + + # Setup lookback block device + self.assertRunOk(f"losetup {lo_dev} {dev_img}") + + # Create and setup dm-dust to simulate a failing block device + # The dev_img file is 1MB: 2048 blocks of 512 bytes each + self.assertRunOk(f"dmsetup create {dm_dev_name} --table '0 2048 dust {lo_dev} 0 512'") + + # Add few bad blocks and enable I/O error emulation + for badblock in [30, 40, 50, 60]: + self.assertRunOk(f"dmsetup message {dm_dev_name} 0 addbadblock {badblock}") + self.assertRunOk(f"dmsetup message {dm_dev_name} 0 enable") + + # Show device mapper status, to make debugging easier + self.assertRunOk(f"dmsetup status {dm_dev_name}") + + # A normal 'dd' is expected to fail with I/O error + cmd = f"dd if={dm_dev} of=/dev/null bs=512" + _, exit_code = self.emulator.run(cmd) + self.assertNotEqual(exit_code, 0) + + # Where a normal 'dd' fails, 'ddrescue' is expected to succeed + self.assertRunOk(f"ddrescue {dm_dev} {ddrescue_img}") + + # ddrescue does not normaly write any output data when there + # is I/O error on the input. The intent is to preserve any + # data that could have been read in a previous pass. There is + # one exception, when the output is a non-existing regular + # file, ddrescue will initialize it with zeroes the first + # time. Since the original image file was also including + # zeroes, the recovered image is expected to be the same as + # the original one. See ddrescue manual: + # https://www.gnu.org/software/ddrescue/manual/ddrescue_manual.html#Introduction + # "Ddrescue does not write zeros to the output when it finds + # bad sectors in the input, and does not truncate the output + # file if not asked to." + # https://www.gnu.org/software/ddrescue/manual/ddrescue_manual.html#Algorithm + # "If the output file is a regular file created by ddrescue, + # the areas marked as bad-sector will contain zeros." + self.assertRunOk(f"cmp {dev_img} {ddrescue_img}") diff --git a/support/testing/tests/package/test_ddrescue/linux-ddrescue.fragment b/support/testing/tests/package/test_ddrescue/linux-ddrescue.fragment new file mode 100644 index 0000000000..5cbe18a89f --- /dev/null +++ b/support/testing/tests/package/test_ddrescue/linux-ddrescue.fragment @@ -0,0 +1,4 @@ +CONFIG_BLK_DEV_LOOP=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DUST=y