summaryrefslogtreecommitdiff
path: root/test/py/tests/test_fs
diff options
context:
space:
mode:
Diffstat (limited to 'test/py/tests/test_fs')
-rw-r--r--test/py/tests/test_fs/conftest.py674
-rw-r--r--test/py/tests/test_fs/fstest_defs.py16
-rw-r--r--test/py/tests/test_fs/fstest_helpers.py13
-rw-r--r--test/py/tests/test_fs/test_basic.py292
-rw-r--r--test/py/tests/test_fs/test_erofs.py220
-rw-r--r--test/py/tests/test_fs/test_ext.py355
-rw-r--r--test/py/tests/test_fs/test_fs_cmd.py13
-rw-r--r--test/py/tests/test_fs/test_fs_fat.py25
-rw-r--r--test/py/tests/test_fs/test_mkdir.py121
-rw-r--r--test/py/tests/test_fs/test_squashfs/sqfs_common.py204
-rw-r--r--test/py/tests/test_fs/test_squashfs/test_sqfs_load.py154
-rw-r--r--test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py148
-rw-r--r--test/py/tests/test_fs/test_symlink.py130
-rw-r--r--test/py/tests/test_fs/test_unlink.py118
14 files changed, 2483 insertions, 0 deletions
diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
new file mode 100644
index 00000000000..fca54488374
--- /dev/null
+++ b/test/py/tests/test_fs/conftest.py
@@ -0,0 +1,674 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+
+import os
+import os.path
+import pytest
+import re
+from subprocess import call, check_call, check_output, CalledProcessError
+from fstest_defs import *
+import u_boot_utils as util
+# pylint: disable=E0611
+from tests import fs_helper
+
+supported_fs_basic = ['fat16', 'fat32', 'ext4']
+supported_fs_ext = ['fat12', 'fat16', 'fat32']
+supported_fs_fat = ['fat12', 'fat16']
+supported_fs_mkdir = ['fat12', 'fat16', 'fat32']
+supported_fs_unlink = ['fat12', 'fat16', 'fat32']
+supported_fs_symlink = ['ext4']
+
+#
+# Filesystem test specific setup
+#
+def pytest_addoption(parser):
+ """Enable --fs-type option.
+
+ See pytest_configure() about how it works.
+
+ Args:
+ parser: Pytest command-line parser.
+
+ Returns:
+ Nothing.
+ """
+ parser.addoption('--fs-type', action='append', default=None,
+ help='Targeting Filesystem Types')
+
+def pytest_configure(config):
+ """Restrict a file system(s) to be tested.
+
+ A file system explicitly named with --fs-type option is selected
+ if it belongs to a default supported_fs_xxx list.
+ Multiple options can be specified.
+
+ Args:
+ config: Pytest configuration.
+
+ Returns:
+ Nothing.
+ """
+ global supported_fs_basic
+ global supported_fs_ext
+ global supported_fs_fat
+ global supported_fs_mkdir
+ global supported_fs_unlink
+ global supported_fs_symlink
+
+ def intersect(listA, listB):
+ return [x for x in listA if x in listB]
+
+ supported_fs = config.getoption('fs_type')
+ if supported_fs:
+ print('*** FS TYPE modified: %s' % supported_fs)
+ supported_fs_basic = intersect(supported_fs, supported_fs_basic)
+ supported_fs_ext = intersect(supported_fs, supported_fs_ext)
+ supported_fs_fat = intersect(supported_fs, supported_fs_fat)
+ supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir)
+ supported_fs_unlink = intersect(supported_fs, supported_fs_unlink)
+ supported_fs_symlink = intersect(supported_fs, supported_fs_symlink)
+
+def pytest_generate_tests(metafunc):
+ """Parametrize fixtures, fs_obj_xxx
+
+ Each fixture will be parametrized with a corresponding support_fs_xxx
+ list.
+
+ Args:
+ metafunc: Pytest test function.
+
+ Returns:
+ Nothing.
+ """
+ if 'fs_obj_basic' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_basic', supported_fs_basic,
+ indirect=True, scope='module')
+ if 'fs_obj_ext' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_ext', supported_fs_ext,
+ indirect=True, scope='module')
+ if 'fs_obj_fat' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_fat', supported_fs_fat,
+ indirect=True, scope='module')
+ if 'fs_obj_mkdir' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir,
+ indirect=True, scope='module')
+ if 'fs_obj_unlink' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
+ indirect=True, scope='module')
+ if 'fs_obj_symlink' in metafunc.fixturenames:
+ metafunc.parametrize('fs_obj_symlink', supported_fs_symlink,
+ indirect=True, scope='module')
+
+#
+# Helper functions
+#
+def fstype_to_ubname(fs_type):
+ """Convert a file system type to an U-Boot specific string
+
+ A generated string can be used as part of file system related commands
+ or a config name in u-boot. Currently fat16 and fat32 are handled
+ specifically.
+
+ Args:
+ fs_type: File system type.
+
+ Return:
+ A corresponding string for file system type.
+ """
+ if re.match('fat', fs_type):
+ return 'fat'
+ else:
+ return fs_type
+
+def check_ubconfig(config, fs_type):
+ """Check whether a file system is enabled in u-boot configuration.
+
+ This function is assumed to be called in a fixture function so that
+ the whole test cases will be skipped if a given file system is not
+ enabled.
+
+ Args:
+ fs_type: File system type.
+
+ Return:
+ Nothing.
+ """
+ if not config.buildconfig.get('config_cmd_%s' % fs_type, None):
+ pytest.skip('.config feature "CMD_%s" not enabled' % fs_type.upper())
+ if not config.buildconfig.get('config_%s_write' % fs_type, None):
+ pytest.skip('.config feature "%s_WRITE" not enabled'
+ % fs_type.upper())
+
+# from test/py/conftest.py
+def tool_is_in_path(tool):
+ """Check whether a given command is available on host.
+
+ Args:
+ tool: Command name.
+
+ Return:
+ True if available, False if not.
+ """
+ for path in os.environ['PATH'].split(os.pathsep):
+ fn = os.path.join(path, tool)
+ if os.path.isfile(fn) and os.access(fn, os.X_OK):
+ return True
+ return False
+
+fuse_mounted = False
+
+def mount_fs(fs_type, device, mount_point):
+ """Mount a volume.
+
+ Args:
+ fs_type: File system type.
+ device: Volume's file name.
+ mount_point: Mount point.
+
+ Return:
+ Nothing.
+ """
+ global fuse_mounted
+
+ try:
+ check_call('guestmount --pid-file guestmount.pid -a %s -m /dev/sda %s'
+ % (device, mount_point), shell=True)
+ fuse_mounted = True
+ return
+ except CalledProcessError:
+ fuse_mounted = False
+
+ mount_opt = 'loop,rw'
+ if re.match('fat', fs_type):
+ mount_opt += ',umask=0000'
+
+ check_call('sudo mount -o %s %s %s'
+ % (mount_opt, device, mount_point), shell=True)
+
+ # may not be effective for some file systems
+ check_call('sudo chmod a+rw %s' % mount_point, shell=True)
+
+def umount_fs(mount_point):
+ """Unmount a volume.
+
+ Args:
+ mount_point: Mount point.
+
+ Return:
+ Nothing.
+ """
+ if fuse_mounted:
+ call('sync')
+ call('guestunmount %s' % mount_point, shell=True)
+
+ try:
+ with open("guestmount.pid", "r") as pidfile:
+ pid = int(pidfile.read())
+ util.waitpid(pid, kill=True)
+ os.remove("guestmount.pid")
+
+ except FileNotFoundError:
+ pass
+
+ else:
+ call('sudo umount %s' % mount_point, shell=True)
+
+#
+# Fixture for basic fs test
+# derived from test/fs/fs-test.sh
+#
+@pytest.fixture()
+def fs_obj_basic(request, u_boot_config):
+ """Set up a file system to be used in basic fs test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for basic fs test, i.e. a triplet of file system type,
+ volume file name and a list of MD5 hashes.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+ small_file = mount_dir + '/' + SMALL_FILE
+ big_file = mount_dir + '/' + BIG_FILE
+
+ try:
+
+ # 3GiB volume
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB')
+ except CalledProcessError as err:
+ pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
+ return
+
+ try:
+ check_call('mkdir -p %s' % mount_dir, shell=True)
+ except CalledProcessError as err:
+ pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Mount the image so we can populate it.
+ mount_fs(fs_type, fs_img, mount_dir)
+ except CalledProcessError as err:
+ pytest.skip('Mounting to folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Create a subdirectory.
+ check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
+
+ # Create big file in this image.
+ # Note that we work only on the start 1MB, couple MBs in the 2GB range
+ # and the last 1 MB of the huge 2.5GB file.
+ # So, just put random values only in those areas.
+ check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+ % big_file, shell=True)
+ check_call('dd if=/dev/urandom of=%s bs=1M count=2 seek=2047'
+ % big_file, shell=True)
+ check_call('dd if=/dev/urandom of=%s bs=1M count=1 seek=2499'
+ % big_file, shell=True)
+
+ # Create a small file in this image.
+ check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+ % small_file, shell=True)
+
+ # Delete the small file copies which possibly are written as part of a
+ # previous test.
+ # check_call('rm -f "%s.w"' % MB1, shell=True)
+ # check_call('rm -f "%s.w2"' % MB1, shell=True)
+
+ # Generate the md5sums of reads that we will test against small file
+ out = check_output(
+ 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+ % small_file, shell=True).decode()
+ md5val = [ out.split()[0] ]
+
+ # Generate the md5sums of reads that we will test against big file
+ # One from beginning of file.
+ out = check_output(
+ 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+ % big_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # One from end of file.
+ out = check_output(
+ 'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum'
+ % big_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # One from the last 1MB chunk of 2GB
+ out = check_output(
+ 'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum'
+ % big_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # One from the start 1MB chunk from 2GB
+ out = check_output(
+ 'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum'
+ % big_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # One 1MB chunk crossing the 2GB boundary
+ out = check_output(
+ 'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum'
+ % big_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ except CalledProcessError as err:
+ pytest.skip('Setup failed for filesystem: ' + fs_type + '. {}'.format(err))
+ umount_fs(mount_dir)
+ return
+ else:
+ umount_fs(mount_dir)
+ yield [fs_ubtype, fs_img, md5val]
+ finally:
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for extended fs test
+#
+@pytest.fixture()
+def fs_obj_ext(request, u_boot_config):
+ """Set up a file system to be used in extended fs test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for extended fs test, i.e. a triplet of file system type,
+ volume file name and a list of MD5 hashes.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+ min_file = mount_dir + '/' + MIN_FILE
+ tmp_file = mount_dir + '/tmpfile'
+
+ try:
+
+ # 128MiB volume
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+ except CalledProcessError as err:
+ pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
+ return
+
+ try:
+ check_call('mkdir -p %s' % mount_dir, shell=True)
+ except CalledProcessError as err:
+ pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Mount the image so we can populate it.
+ mount_fs(fs_type, fs_img, mount_dir)
+ except CalledProcessError as err:
+ pytest.skip('Mounting to folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Create a test directory
+ check_call('mkdir %s/dir1' % mount_dir, shell=True)
+
+ # Create a small file and calculate md5
+ check_call('dd if=/dev/urandom of=%s bs=1K count=20'
+ % min_file, shell=True)
+ out = check_output(
+ 'dd if=%s bs=1K 2> /dev/null | md5sum'
+ % min_file, shell=True).decode()
+ md5val = [ out.split()[0] ]
+
+ # Calculate md5sum of Test Case 4
+ check_call('dd if=%s of=%s bs=1K count=20'
+ % (min_file, tmp_file), shell=True)
+ check_call('dd if=%s of=%s bs=1K seek=5 count=20'
+ % (min_file, tmp_file), shell=True)
+ out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+ % tmp_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # Calculate md5sum of Test Case 5
+ check_call('dd if=%s of=%s bs=1K count=20'
+ % (min_file, tmp_file), shell=True)
+ check_call('dd if=%s of=%s bs=1K seek=5 count=5'
+ % (min_file, tmp_file), shell=True)
+ out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+ % tmp_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ # Calculate md5sum of Test Case 7
+ check_call('dd if=%s of=%s bs=1K count=20'
+ % (min_file, tmp_file), shell=True)
+ check_call('dd if=%s of=%s bs=1K seek=20 count=20'
+ % (min_file, tmp_file), shell=True)
+ out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+ % tmp_file, shell=True).decode()
+ md5val.append(out.split()[0])
+
+ check_call('rm %s' % tmp_file, shell=True)
+ except CalledProcessError:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ umount_fs(mount_dir)
+ return
+ else:
+ umount_fs(mount_dir)
+ yield [fs_ubtype, fs_img, md5val]
+ finally:
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for mkdir test
+#
+@pytest.fixture()
+def fs_obj_mkdir(request, u_boot_config):
+ """Set up a file system to be used in mkdir test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for mkdir test, i.e. a duplet of file system type and
+ volume file name.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ try:
+ # 128MiB volume
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+ except:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ return
+ else:
+ yield [fs_ubtype, fs_img]
+ call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for unlink test
+#
+@pytest.fixture()
+def fs_obj_unlink(request, u_boot_config):
+ """Set up a file system to be used in unlink test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for unlink test, i.e. a duplet of file system type and
+ volume file name.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+ try:
+
+ # 128MiB volume
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+ except CalledProcessError as err:
+ pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
+ return
+
+ try:
+ check_call('mkdir -p %s' % mount_dir, shell=True)
+ except CalledProcessError as err:
+ pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Mount the image so we can populate it.
+ mount_fs(fs_type, fs_img, mount_dir)
+ except CalledProcessError as err:
+ pytest.skip('Mounting to folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Test Case 1 & 3
+ check_call('mkdir %s/dir1' % mount_dir, shell=True)
+ check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1'
+ % mount_dir, shell=True)
+ check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1'
+ % mount_dir, shell=True)
+
+ # Test Case 2
+ check_call('mkdir %s/dir2' % mount_dir, shell=True)
+ for i in range(0, 20):
+ check_call('mkdir %s/dir2/0123456789abcdef%02x'
+ % (mount_dir, i), shell=True)
+
+ # Test Case 4
+ check_call('mkdir %s/dir4' % mount_dir, shell=True)
+
+ # Test Case 5, 6 & 7
+ check_call('mkdir %s/dir5' % mount_dir, shell=True)
+ check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1'
+ % mount_dir, shell=True)
+
+ except CalledProcessError:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ umount_fs(mount_dir)
+ return
+ else:
+ umount_fs(mount_dir)
+ yield [fs_ubtype, fs_img]
+ finally:
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for symlink fs test
+#
+@pytest.fixture()
+def fs_obj_symlink(request, u_boot_config):
+ """Set up a file system to be used in symlink fs test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for basic fs test, i.e. a triplet of file system type,
+ volume file name and a list of MD5 hashes.
+ """
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+ small_file = mount_dir + '/' + SMALL_FILE
+ medium_file = mount_dir + '/' + MEDIUM_FILE
+
+ try:
+
+ # 1GiB volume
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x40000000, '1GB')
+ except CalledProcessError as err:
+ pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
+ return
+
+ try:
+ check_call('mkdir -p %s' % mount_dir, shell=True)
+ except CalledProcessError as err:
+ pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Mount the image so we can populate it.
+ mount_fs(fs_type, fs_img, mount_dir)
+ except CalledProcessError as err:
+ pytest.skip('Mounting to folder failed for filesystem: ' + fs_type + '. {}'.format(err))
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+ return
+
+ try:
+ # Create a subdirectory.
+ check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
+
+ # Create a small file in this image.
+ check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+ % small_file, shell=True)
+
+ # Create a medium file in this image.
+ check_call('dd if=/dev/urandom of=%s bs=10M count=1'
+ % medium_file, shell=True)
+
+ # Generate the md5sums of reads that we will test against small file
+ out = check_output(
+ 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+ % small_file, shell=True).decode()
+ md5val = [out.split()[0]]
+ out = check_output(
+ 'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum'
+ % medium_file, shell=True).decode()
+ md5val.extend([out.split()[0]])
+
+ except CalledProcessError:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ umount_fs(mount_dir)
+ return
+ else:
+ umount_fs(mount_dir)
+ yield [fs_ubtype, fs_img, md5val]
+ finally:
+ call('rmdir %s' % mount_dir, shell=True)
+ call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for fat test
+#
+@pytest.fixture()
+def fs_obj_fat(request, u_boot_config):
+ """Set up a file system to be used in fat test.
+
+ Args:
+ request: Pytest request object.
+ u_boot_config: U-Boot configuration.
+
+ Return:
+ A fixture for fat test, i.e. a duplet of file system type and
+ volume file name.
+ """
+
+ # the maximum size of a FAT12 filesystem resulting in 4084 clusters
+ MAX_FAT12_SIZE = 261695 * 1024
+
+ # the minimum size of a FAT16 filesystem that can be created with
+ # mkfs.vfat resulting in 4087 clusters
+ MIN_FAT16_SIZE = 8208 * 1024
+
+ fs_type = request.param
+ fs_img = ''
+
+ fs_ubtype = fstype_to_ubname(fs_type)
+ check_ubconfig(u_boot_config, fs_ubtype)
+
+ fs_size = MAX_FAT12_SIZE if fs_type == 'fat12' else MIN_FAT16_SIZE
+
+ try:
+ # the volume size depends on the filesystem
+ fs_img = fs_helper.mk_fs(u_boot_config, fs_type, fs_size, f'{fs_size}', 1024)
+ except:
+ pytest.skip('Setup failed for filesystem: ' + fs_type)
+ return
+ else:
+ yield [fs_ubtype, fs_img]
+ call('rm -f %s' % fs_img, shell=True)
diff --git a/test/py/tests/test_fs/fstest_defs.py b/test/py/tests/test_fs/fstest_defs.py
new file mode 100644
index 00000000000..35b2bb65183
--- /dev/null
+++ b/test/py/tests/test_fs/fstest_defs.py
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+# $MIN_FILE is the name of the 20KB file in the file system image
+MIN_FILE='testfile'
+
+# $SMALL_FILE is the name of the 1MB file in the file system image
+SMALL_FILE='1MB.file'
+
+# $MEDIUM_FILE is the name of the 10MB file in the file system image
+MEDIUM_FILE='10MB.file'
+
+# $BIG_FILE is the name of the 2.5GB file in the file system image
+BIG_FILE='2.5GB.file'
+
+ADDR=0x01000008
+LENGTH=0x00100000
diff --git a/test/py/tests/test_fs/fstest_helpers.py b/test/py/tests/test_fs/fstest_helpers.py
new file mode 100644
index 00000000000..faec2982489
--- /dev/null
+++ b/test/py/tests/test_fs/fstest_helpers.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2019, Texas Instrument
+# Author: JJ Hiblot <jjhiblot@ti.com>
+#
+
+from subprocess import check_call, CalledProcessError
+
+def assert_fs_integrity(fs_type, fs_img):
+ try:
+ if fs_type == 'ext4':
+ check_call('fsck.ext4 -n -f %s' % fs_img, shell=True)
+ except CalledProcessError:
+ raise
diff --git a/test/py/tests/test_fs/test_basic.py b/test/py/tests/test_fs/test_basic.py
new file mode 100644
index 00000000000..71f3e86fb18
--- /dev/null
+++ b/test/py/tests/test_fs/test_basic.py
@@ -0,0 +1,292 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:Basic Test
+
+"""
+This test verifies basic read/write operation on file system.
+"""
+
+import pytest
+import re
+from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestFsBasic(object):
+ def test_fs1(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 1 - ls command, listing a root directory and invalid directory
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 1a - ls'):
+ # Test Case 1 - ls
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sls host 0:0' % fs_type])
+ assert(re.search('2621440000 *%s' % BIG_FILE, ''.join(output)))
+ assert(re.search('1048576 *%s' % SMALL_FILE, ''.join(output)))
+
+ with u_boot_console.log.section('Test Case 1b - ls (invalid dir)'):
+ # In addition, test with a nonexistent directory to see if we crash.
+ output = u_boot_console.run_command(
+ '%sls host 0:0 invalid_d' % fs_type)
+ if fs_type == 'ext4':
+ assert('Can not find directory' in output)
+ else:
+ assert('' == output)
+
+ def test_fs2(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 2 - size command for a small file
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 2a - size (small)'):
+ # 1MB is 0x0010 0000
+ # Test Case 2a - size of small file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%ssize host 0:0 /%s' % (fs_type, SMALL_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ with u_boot_console.log.section('Test Case 2b - size (/../<file>)'):
+ # Test Case 2b - size of small file via a path using '..'
+ output = u_boot_console.run_command_list([
+ '%ssize host 0:0 /SUBDIR/../%s' % (fs_type, SMALL_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ def test_fs3(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 3 - size command for a large file
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 3 - size (large)'):
+ # 2.5GB (1024*1024*2500) is 0x9C40 0000
+ # Test Case 3 - size of big file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%ssize host 0:0 /%s' % (fs_type, BIG_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=9c400000' in ''.join(output))
+
+ def test_fs4(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 4 - load a small file, 1MB
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 4 - load (small)'):
+ # Test Case 4a - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 4b - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+
+ def test_fs5(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 5 - load, reading first 1MB of 3GB file
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 5 - load (first 1MB)'):
+ # Test Case 5a - First 1MB of big file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s %x 0x0' % (fs_type, ADDR, BIG_FILE, LENGTH),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 5b - First 1MB of big file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+
+ def test_fs6(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 6 - load, reading last 1MB of 3GB file
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 6 - load (last 1MB)'):
+ # fails for ext as no offset support
+ # Test Case 6a - Last 1MB of big file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s %x 0x9c300000'
+ % (fs_type, ADDR, BIG_FILE, LENGTH),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 6b - Last 1MB of big file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[2] in ''.join(output))
+
+ def test_fs7(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 7 - load, 1MB from the last 1MB in 2GB
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 7 - load (last 1MB in 2GB)'):
+ # fails for ext as no offset support
+ # Test Case 7a - One from the last 1MB chunk of 2GB
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s %x 0x7ff00000'
+ % (fs_type, ADDR, BIG_FILE, LENGTH),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 7b - One from the last 1MB chunk of 2GB
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[3] in ''.join(output))
+
+ def test_fs8(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 8 - load, reading first 1MB in 2GB
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 8 - load (first 1MB in 2GB)'):
+ # fails for ext as no offset support
+ # Test Case 8a - One from the start 1MB chunk from 2GB
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s %x 0x80000000'
+ % (fs_type, ADDR, BIG_FILE, LENGTH),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 8b - One from the start 1MB chunk from 2GB
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[4] in ''.join(output))
+
+ def test_fs9(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 9 - load, 1MB crossing 2GB boundary
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 9 - load (crossing 2GB boundary)'):
+ # fails for ext as no offset support
+ # Test Case 9a - One 1MB chunk crossing the 2GB boundary
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s %x 0x7ff80000'
+ % (fs_type, ADDR, BIG_FILE, LENGTH),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 9b - One 1MB chunk crossing the 2GB boundary
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[5] in ''.join(output))
+
+ def test_fs10(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 10 - load, reading beyond file end'):
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 10 - load (beyond file end)'):
+ # Generic failure case
+ # Test Case 10 - 2MB chunk from the last 1MB of big file
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s 0x00200000 0x9c300000'
+ % (fs_type, ADDR, BIG_FILE),
+ 'printenv filesize',
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ def test_fs11(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 11 - write'
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 11 - write'):
+ # Read 1MB from small file
+ # Write it back to test the writes
+ # Test Case 11a - Check that the write succeeded
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ '%swrite host 0:0 %x /%s.w $filesize'
+ % (fs_type, ADDR, SMALL_FILE)])
+ assert('1048576 bytes written' in ''.join(output))
+
+ # Test Case 11b - Check md5 of written to is same
+ # as the one read from
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s.w' % (fs_type, ADDR, SMALL_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs12(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 12 - write to "." directory
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 12 - write (".")'):
+ # Next test case checks writing a file whose dirent
+ # is the first in the block, which is always true for "."
+ # The write should fail, but the lookup should work
+ # Test Case 12 - Check directory traversal
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)])
+ assert('Unable to write' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs13(self, u_boot_console, fs_obj_basic):
+ """
+ Test Case 13 - write to a file with "/./<filename>"
+ """
+ fs_type,fs_img,md5val = fs_obj_basic
+ with u_boot_console.log.section('Test Case 13 - write ("./<file>")'):
+ # Read 1MB from small file
+ # Write it via "same directory", i.e. "." dirent
+ # Test Case 13a - Check directory traversal
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ '%swrite host 0:0 %x /./%s2 $filesize'
+ % (fs_type, ADDR, SMALL_FILE)])
+ assert('1048576 bytes written' in ''.join(output))
+
+ # Test Case 13b - Check md5 of written to is same
+ # as the one read from
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /./%s2' % (fs_type, ADDR, SMALL_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+
+ # Test Case 13c - Check md5 of written to is same
+ # as the one read from
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /%s2' % (fs_type, ADDR, SMALL_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_erofs.py b/test/py/tests/test_fs/test_erofs.py
new file mode 100644
index 00000000000..87ad8f2d5fd
--- /dev/null
+++ b/test/py/tests/test_fs/test_erofs.py
@@ -0,0 +1,220 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (C) 2022 Huang Jianan <jnhuang95@gmail.com>
+# Author: Huang Jianan <jnhuang95@gmail.com>
+
+import os
+import pytest
+import shutil
+import subprocess
+
+EROFS_SRC_DIR = 'erofs_src_dir'
+EROFS_IMAGE_NAME = 'erofs.img'
+
+def generate_file(name, size):
+ """
+ Generates a file filled with 'x'.
+ """
+ content = 'x' * size
+ file = open(name, 'w')
+ file.write(content)
+ file.close()
+
+def make_erofs_image(build_dir):
+ """
+ Makes the EROFS images used for the test.
+
+ The image is generated at build_dir with the following structure:
+ erofs_src_dir/
+ ├── f4096
+ ├── f7812
+ ├── subdir/
+ │   └── subdir-file
+ ├── symdir -> subdir
+ └── symfile -> f5096
+ """
+ root = os.path.join(build_dir, EROFS_SRC_DIR)
+ os.makedirs(root)
+
+ # 4096: uncompressed file
+ generate_file(os.path.join(root, 'f4096'), 4096)
+
+ # 7812: Compressed file
+ generate_file(os.path.join(root, 'f7812'), 7812)
+
+ # sub-directory with a single file inside
+ subdir_path = os.path.join(root, 'subdir')
+ os.makedirs(subdir_path)
+ generate_file(os.path.join(subdir_path, 'subdir-file'), 100)
+
+ # symlink
+ os.symlink('subdir', os.path.join(root, 'symdir'))
+ os.symlink('f7812', os.path.join(root, 'symfile'))
+
+ input_path = os.path.join(build_dir, EROFS_SRC_DIR)
+ output_path = os.path.join(build_dir, EROFS_IMAGE_NAME)
+ args = ' '.join([output_path, input_path])
+ subprocess.run(['mkfs.erofs -zlz4 ' + args], shell=True, check=True,
+ stdout=subprocess.DEVNULL)
+
+def clean_erofs_image(build_dir):
+ """
+ Deletes the image and src_dir at build_dir.
+ """
+ path = os.path.join(build_dir, EROFS_SRC_DIR)
+ shutil.rmtree(path)
+ image_path = os.path.join(build_dir, EROFS_IMAGE_NAME)
+ os.remove(image_path)
+
+def erofs_ls_at_root(u_boot_console):
+ """
+ Test if all the present files and directories were listed.
+ """
+ no_slash = u_boot_console.run_command('erofsls host 0')
+ slash = u_boot_console.run_command('erofsls host 0 /')
+ assert no_slash == slash
+
+ expected_lines = ['./', '../', '4096 f4096', '7812 f7812', 'subdir/',
+ '<SYM> symdir', '<SYM> symfile', '4 file(s), 3 dir(s)']
+
+ output = u_boot_console.run_command('erofsls host 0')
+ for line in expected_lines:
+ assert line in output
+
+def erofs_ls_at_subdir(u_boot_console):
+ """
+ Test if the path resolution works.
+ """
+ expected_lines = ['./', '../', '100 subdir-file', '1 file(s), 2 dir(s)']
+ output = u_boot_console.run_command('erofsls host 0 subdir')
+ for line in expected_lines:
+ assert line in output
+
+def erofs_ls_at_symlink(u_boot_console):
+ """
+ Test if the symbolic link's target resolution works.
+ """
+ output = u_boot_console.run_command('erofsls host 0 symdir')
+ output_subdir = u_boot_console.run_command('erofsls host 0 subdir')
+ assert output == output_subdir
+
+ expected_lines = ['./', '../', '100 subdir-file', '1 file(s), 2 dir(s)']
+ for line in expected_lines:
+ assert line in output
+
+def erofs_ls_at_non_existent_dir(u_boot_console):
+ """
+ Test if the EROFS support will crash when get a nonexistent directory.
+ """
+ out_non_existent = u_boot_console.run_command('erofsls host 0 fff')
+ out_not_dir = u_boot_console.run_command('erofsls host 0 f1000')
+ assert out_non_existent == out_not_dir
+ assert '' in out_non_existent
+
+def erofs_load_files(u_boot_console, files, sizes, address):
+ """
+ Loads files and asserts their checksums.
+ """
+ build_dir = u_boot_console.config.build_dir
+ for (file, size) in zip(files, sizes):
+ out = u_boot_console.run_command('erofsload host 0 {} {}'.format(address, file))
+
+ # check if the right amount of bytes was read
+ assert size in out
+
+ # calculate u-boot file's checksum
+ out = u_boot_console.run_command('md5sum {} {}'.format(address, hex(int(size))))
+ u_boot_checksum = out.split()[-1]
+
+ # calculate original file's checksum
+ original_file_path = os.path.join(build_dir, EROFS_SRC_DIR + '/' + file)
+ out = subprocess.run(['md5sum ' + original_file_path], shell=True, check=True,
+ capture_output=True, text=True)
+ original_checksum = out.stdout.split()[0]
+
+ # compare checksum
+ assert u_boot_checksum == original_checksum
+
+def erofs_load_files_at_root(u_boot_console):
+ """
+ Test load file from the root directory.
+ """
+ files = ['f4096', 'f7812']
+ sizes = ['4096', '7812']
+ address = '$kernel_addr_r'
+ erofs_load_files(u_boot_console, files, sizes, address)
+
+def erofs_load_files_at_subdir(u_boot_console):
+ """
+ Test load file from the subdirectory.
+ """
+ files = ['subdir/subdir-file']
+ sizes = ['100']
+ address = '$kernel_addr_r'
+ erofs_load_files(u_boot_console, files, sizes, address)
+
+def erofs_load_files_at_symlink(u_boot_console):
+ """
+ Test load file from the symlink.
+ """
+ files = ['symfile']
+ sizes = ['7812']
+ address = '$kernel_addr_r'
+ erofs_load_files(u_boot_console, files, sizes, address)
+
+def erofs_load_non_existent_file(u_boot_console):
+ """
+ Test if the EROFS support will crash when load a nonexistent file.
+ """
+ address = '$kernel_addr_r'
+ file = 'non-existent'
+ out = u_boot_console.run_command('erofsload host 0 {} {}'.format(address, file))
+ assert 'Failed to load' in out
+
+def erofs_run_all_tests(u_boot_console):
+ """
+ Runs all test cases.
+ """
+ erofs_ls_at_root(u_boot_console)
+ erofs_ls_at_subdir(u_boot_console)
+ erofs_ls_at_symlink(u_boot_console)
+ erofs_ls_at_non_existent_dir(u_boot_console)
+ erofs_load_files_at_root(u_boot_console)
+ erofs_load_files_at_subdir(u_boot_console)
+ erofs_load_files_at_symlink(u_boot_console)
+ erofs_load_non_existent_file(u_boot_console)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_fs_generic')
+@pytest.mark.buildconfigspec('cmd_erofs')
+@pytest.mark.buildconfigspec('fs_erofs')
+@pytest.mark.requiredtool('mkfs.erofs')
+@pytest.mark.requiredtool('md5sum')
+
+def test_erofs(u_boot_console):
+ """
+ Executes the erofs test suite.
+ """
+ build_dir = u_boot_console.config.build_dir
+
+ # If the EFI subsystem is enabled and initialized, EFI subsystem tries to
+ # add EFI boot option when the new disk is detected. If there is no EFI
+ # System Partition exists, EFI subsystem outputs error messages and
+ # it ends up with test failure.
+ # Restart U-Boot to clear the previous state.
+ # TODO: Ideally EFI test cases need to be fixed, but it will
+ # increase the number of system reset.
+ u_boot_console.restart_uboot()
+
+ try:
+ # setup test environment
+ make_erofs_image(build_dir)
+ image_path = os.path.join(build_dir, EROFS_IMAGE_NAME)
+ u_boot_console.run_command('host bind 0 {}'.format(image_path))
+ # run all tests
+ erofs_run_all_tests(u_boot_console)
+ except:
+ clean_erofs_image(build_dir)
+ raise AssertionError
+
+ # clean test environment
+ clean_erofs_image(build_dir)
diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py
new file mode 100644
index 00000000000..05fefa53a0e
--- /dev/null
+++ b/test/py/tests/test_fs/test_ext.py
@@ -0,0 +1,355 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:Exntented Test
+
+"""
+This test verifies extended write operation on file system.
+"""
+
+import os.path
+import pytest
+import re
+from subprocess import check_output
+from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
+
+PLAIN_FILE='abcdefgh.txt'
+MANGLE_FILE='abcdefghi.txt'
+
+def str2fat(long_filename):
+ splitext = os.path.splitext(long_filename.upper())
+ name = splitext[0]
+ ext = splitext[1][1:]
+ if len(name) > 8:
+ name = '%s~1' % name[:6]
+ return '%-8s %s' % (name, ext)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestFsExt(object):
+ def test_fs_ext1(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 1 - write a file with absolute path
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 1 - write with abs path'):
+ # Test Case 1a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w1 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ assert('20480 bytes written' in ''.join(output))
+
+ # Test Case 1b - Check md5 of file content
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /dir1/%s.w1' % (fs_type, ADDR, MIN_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext2(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 2 - write to a file with relative path
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 2 - write with rel path'):
+ # Test Case 2a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x dir1/%s.w2 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ assert('20480 bytes written' in ''.join(output))
+
+ # Test Case 2b - Check md5 of file content
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x dir1/%s.w2' % (fs_type, ADDR, MIN_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext3(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 3 - write to a file with invalid path
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 3 - write with invalid path'):
+ # Test Case 3 - Check if command expectedly failed
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/none/%s.w3 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ assert('Unable to write file /dir1/none/' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext4(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 4 - write at non-zero offset, enlarging file size
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 4 - write at non-zero offset, enlarging file size'):
+ # Test Case 4a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w4 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/%s.w4 $filesize 0x1400'
+ % (fs_type, ADDR, MIN_FILE))
+ assert('20480 bytes written' in output)
+
+ # Test Case 4b - Check size of written file
+ output = u_boot_console.run_command_list([
+ '%ssize host 0:0 /dir1/%s.w4' % (fs_type, MIN_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=6400' in ''.join(output))
+
+ # Test Case 4c - Check md5 of file content
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /dir1/%s.w4' % (fs_type, ADDR, MIN_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext5(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 5 - write at non-zero offset, shrinking file size
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 5 - write at non-zero offset, shrinking file size'):
+ # Test Case 5a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w5 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/%s.w5 0x1400 0x1400'
+ % (fs_type, ADDR, MIN_FILE))
+ assert('5120 bytes written' in output)
+
+ # Test Case 5b - Check size of written file
+ output = u_boot_console.run_command_list([
+ '%ssize host 0:0 /dir1/%s.w5' % (fs_type, MIN_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=2800' in ''.join(output))
+
+ # Test Case 5c - Check md5 of file content
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /dir1/%s.w5' % (fs_type, ADDR, MIN_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[2] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext6(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 6 - write nothing at the start, truncating to zero
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 6 - write nothing at the start, truncating to zero'):
+ # Test Case 6a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w6 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/%s.w6 0 0'
+ % (fs_type, ADDR, MIN_FILE))
+ assert('0 bytes written' in output)
+
+ # Test Case 6b - Check size of written file
+ output = u_boot_console.run_command_list([
+ '%ssize host 0:0 /dir1/%s.w6' % (fs_type, MIN_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=0' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext7(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 7 - write at the end (append)
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 7 - write at the end (append)'):
+ # Test Case 7a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w7 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/%s.w7 $filesize $filesize'
+ % (fs_type, ADDR, MIN_FILE))
+ assert('20480 bytes written' in output)
+
+ # Test Case 7b - Check size of written file
+ output = u_boot_console.run_command_list([
+ '%ssize host 0:0 /dir1/%s.w7' % (fs_type, MIN_FILE),
+ 'printenv filesize',
+ 'setenv filesize'])
+ assert('filesize=a000' in ''.join(output))
+
+ # Test Case 7c - Check md5 of file content
+ output = u_boot_console.run_command_list([
+ 'mw.b %x 00 100' % ADDR,
+ '%sload host 0:0 %x /dir1/%s.w7' % (fs_type, ADDR, MIN_FILE),
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[3] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext8(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 8 - write at offset beyond the end of file
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 8 - write beyond the end'):
+ # Test Case 8a - Check if command expectedly failed
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w8 $filesize'
+ % (fs_type, ADDR, MIN_FILE)])
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x'
+ % (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400))
+ assert('Unable to write file /dir1' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext9(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 9 - write to a non-existing file at non-zero offset
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 9 - write to non-existing file with non-zero offset'):
+ # Test Case 9a - Check if command expectedly failed
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+ '%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400'
+ % (fs_type, ADDR, MIN_FILE)])
+ assert('Unable to write file /dir1' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext10(self, u_boot_console, fs_obj_ext):
+ """
+ 'Test Case 10 - create/delete as many directories under root directory
+ as amount of directory entries goes beyond one cluster size)'
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 10 - create/delete (many)'):
+ # Test Case 10a - Create many files
+ # Please note that the size of directory entry is 32 bytes.
+ # So one typical cluster may holds 64 (2048/32) entries.
+ output = u_boot_console.run_command(
+ 'host bind 0 %s' % fs_img)
+
+ for i in range(0, 66):
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /FILE0123456789_%02x 100'
+ % (fs_type, ADDR, i))
+ output = u_boot_console.run_command('%sls host 0:0 /' % fs_type)
+ assert('FILE0123456789_00' in output)
+ assert('FILE0123456789_41' in output)
+
+ # Test Case 10b - Delete many files
+ for i in range(0, 66):
+ output = u_boot_console.run_command(
+ '%srm host 0:0 /FILE0123456789_%02x'
+ % (fs_type, i))
+ output = u_boot_console.run_command('%sls host 0:0 /' % fs_type)
+ assert(not 'FILE0123456789_00' in output)
+ assert(not 'FILE0123456789_41' in output)
+
+ # Test Case 10c - Create many files again
+ # Please note no.64 and 65 are intentionally re-created
+ for i in range(64, 128):
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /FILE0123456789_%02x 100'
+ % (fs_type, ADDR, i))
+ output = u_boot_console.run_command('%sls host 0:0 /' % fs_type)
+ assert('FILE0123456789_40' in output)
+ assert('FILE0123456789_79' in output)
+
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext11(self, u_boot_console, fs_obj_ext):
+ """
+ 'Test Case 11 - create/delete as many directories under non-root
+ directory as amount of directory entries goes beyond one cluster size)'
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 11 - create/delete (many)'):
+ # Test Case 11a - Create many files
+ # Please note that the size of directory entry is 32 bytes.
+ # So one typical cluster may holds 64 (2048/32) entries.
+ output = u_boot_console.run_command(
+ 'host bind 0 %s' % fs_img)
+
+ for i in range(0, 66):
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/FILE0123456789_%02x 100'
+ % (fs_type, ADDR, i))
+ output = u_boot_console.run_command('%sls host 0:0 /dir1' % fs_type)
+ assert('FILE0123456789_00' in output)
+ assert('FILE0123456789_41' in output)
+
+ # Test Case 11b - Delete many files
+ for i in range(0, 66):
+ output = u_boot_console.run_command(
+ '%srm host 0:0 /dir1/FILE0123456789_%02x'
+ % (fs_type, i))
+ output = u_boot_console.run_command('%sls host 0:0 /dir1' % fs_type)
+ assert(not 'FILE0123456789_00' in output)
+ assert(not 'FILE0123456789_41' in output)
+
+ # Test Case 11c - Create many files again
+ # Please note no.64 and 65 are intentionally re-created
+ for i in range(64, 128):
+ output = u_boot_console.run_command(
+ '%swrite host 0:0 %x /dir1/FILE0123456789_%02x 100'
+ % (fs_type, ADDR, i))
+ output = u_boot_console.run_command('%sls host 0:0 /dir1' % fs_type)
+ assert('FILE0123456789_40' in output)
+ assert('FILE0123456789_79' in output)
+
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_fs_ext12(self, u_boot_console, fs_obj_ext):
+ """
+ Test Case 12 - write plain and mangle file
+ """
+ fs_type,fs_img,md5val = fs_obj_ext
+ with u_boot_console.log.section('Test Case 12 - write plain and mangle file'):
+ # Test Case 12a - Check if command successfully returned
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%swrite host 0:0 %x /%s 0'
+ % (fs_type, ADDR, PLAIN_FILE),
+ '%swrite host 0:0 %x /%s 0'
+ % (fs_type, ADDR, MANGLE_FILE)])
+ assert('0 bytes written' in ''.join(output))
+ # Test Case 12b - Read file system content
+ output = check_output('mdir -i %s' % fs_img, shell=True).decode()
+ # Test Case 12c - Check if short filename is not mangled
+ assert(str2fat(PLAIN_FILE) in ''.join(output))
+ # Test Case 12d - Check if long filename is mangled
+ assert(str2fat(MANGLE_FILE) in ''.join(output))
+
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_fs_cmd.py b/test/py/tests/test_fs/test_fs_cmd.py
new file mode 100644
index 00000000000..700cf3591de
--- /dev/null
+++ b/test/py/tests/test_fs/test_fs_cmd.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020
+# Niel Fourie, DENX Software Engineering, lusus@denx.de
+
+import pytest
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_fs_generic')
+def test_fstypes(u_boot_console):
+ """Test that `fstypes` prints a result which includes `sandbox`."""
+ output = u_boot_console.run_command('fstypes')
+ assert "Supported filesystems:" in output
+ assert "sandbox" in output
diff --git a/test/py/tests/test_fs/test_fs_fat.py b/test/py/tests/test_fs/test_fs_fat.py
new file mode 100644
index 00000000000..4009d0b63a3
--- /dev/null
+++ b/test/py/tests/test_fs/test_fs_fat.py
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2023 Weidmüller Interface GmbH & Co. KG
+# Author: Christian Taedcke <christian.taedcke@weidmueller.com>
+#
+# U-Boot File System: FAT Test
+
+"""
+This test verifies fat specific file system behaviour.
+"""
+
+import pytest
+import re
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestFsFat(object):
+ def test_fs_fat1(self, u_boot_console, fs_obj_fat):
+ """Test that `fstypes` prints a result which includes `sandbox`."""
+ fs_type,fs_img = fs_obj_fat
+ with u_boot_console.log.section('Test Case 1 - fatinfo'):
+ # Test Case 1 - ls
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'fatinfo host 0:0'])
+ assert(re.search('Filesystem: %s' % fs_type.upper(), ''.join(output)))
diff --git a/test/py/tests/test_fs/test_mkdir.py b/test/py/tests/test_fs/test_mkdir.py
new file mode 100644
index 00000000000..fa9561ec359
--- /dev/null
+++ b/test/py/tests/test_fs/test_mkdir.py
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:mkdir Test
+
+"""
+This test verifies mkdir operation on file system.
+"""
+
+import pytest
+from fstest_helpers import assert_fs_integrity
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestMkdir(object):
+ def test_mkdir1(self, u_boot_console, fs_obj_mkdir):
+ """
+ Test Case 1 - create a directory under a root
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 1 - mkdir'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 dir1' % fs_type,
+ '%sls host 0:0 /' % fs_type])
+ assert('dir1/' in ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir1' % fs_type)
+ assert('./' in output)
+ assert('../' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+
+ def test_mkdir2(self, u_boot_console, fs_obj_mkdir):
+ """
+ Test Case 2 - create a directory under a sub-directory
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 2 - mkdir (sub-sub directory)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 dir1/dir2' % fs_type,
+ '%sls host 0:0 dir1' % fs_type])
+ assert('dir2/' in ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir1/dir2' % fs_type)
+ assert('./' in output)
+ assert('../' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_mkdir3(self, u_boot_console, fs_obj_mkdir):
+ """
+ Test Case 3 - trying to create a directory with a non-existing
+ path should fail
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 3 - mkdir (non-existing path)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 none/dir3' % fs_type])
+ assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_mkdir4(self, u_boot_console, fs_obj_mkdir):
+ """
+ Test Case 4 - trying to create "." should fail
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 4 - mkdir (".")'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 .' % fs_type])
+ assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_mkdir5(self, u_boot_console, fs_obj_mkdir):
+ """
+ Test Case 5 - trying to create ".." should fail
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 5 - mkdir ("..")'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 ..' % fs_type])
+ assert('Unable to create a directory' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_mkdir6(self, u_boot_console, fs_obj_mkdir):
+ """
+ 'Test Case 6 - create as many directories as amount of directory
+ entries goes beyond a cluster size)'
+ """
+ fs_type,fs_img = fs_obj_mkdir
+ with u_boot_console.log.section('Test Case 6 - mkdir (create many)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%smkdir host 0:0 dir6' % fs_type,
+ '%sls host 0:0 /' % fs_type])
+ assert('dir6/' in ''.join(output))
+
+ for i in range(0, 20):
+ output = u_boot_console.run_command(
+ '%smkdir host 0:0 dir6/0123456789abcdef%02x'
+ % (fs_type, i))
+ output = u_boot_console.run_command('%sls host 0:0 dir6' % fs_type)
+ assert('0123456789abcdef00/' in output)
+ assert('0123456789abcdef13/' in output)
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir6/0123456789abcdef13/.' % fs_type)
+ assert('./' in output)
+ assert('../' in output)
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type)
+ assert('0123456789abcdef00/' in output)
+ assert('0123456789abcdef13/' in output)
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_squashfs/sqfs_common.py b/test/py/tests/test_fs/test_squashfs/sqfs_common.py
new file mode 100644
index 00000000000..d1621dcce3a
--- /dev/null
+++ b/test/py/tests/test_fs/test_squashfs/sqfs_common.py
@@ -0,0 +1,204 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 Bootlin
+# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
+
+import os
+import shutil
+import subprocess
+
+""" standard test images table: Each table item is a key:value pair
+representing the output image name and its respective mksquashfs options.
+This table should be modified only when adding support for new compression
+algorithms. The 'default' case takes no options but the input and output
+names, so it must be assigned with an empty string.
+"""
+STANDARD_TABLE = {
+ 'default' : '',
+ 'lzo_comp_frag' : '',
+ 'lzo_frag' : '',
+ 'lzo_no_frag' : '',
+ 'zstd_comp_frag' : '',
+ 'zstd_frag' : '',
+ 'zstd_no_frag' : '',
+ 'gzip_comp_frag' : '',
+ 'gzip_frag' : '',
+ 'gzip_no_frag' : ''
+}
+
+""" EXTRA_TABLE: Set this table's keys and values if you want to make squashfs
+images with your own customized options.
+"""
+EXTRA_TABLE = {}
+
+# path to source directory used to make squashfs test images
+SQFS_SRC_DIR = 'sqfs_src_dir'
+
+def get_opts_list():
+ """ Combines fragmentation and compression options into a list of strings.
+
+ opts_list's firts item is an empty string as STANDARD_TABLE's first item is
+ the 'default' case.
+
+ Returns:
+ A list of strings whose items are formed by a compression and a
+ fragmentation option joined by a whitespace.
+ """
+ # supported compression options only
+ comp_opts = ['-comp lzo', '-comp zstd', '-comp gzip']
+ # file fragmentation options
+ frag_opts = ['-always-use-fragments', '-always-use-fragments -noF', '-no-fragments']
+
+ opts_list = [' ']
+ for comp_opt in comp_opts:
+ for frag_opt in frag_opts:
+ opts_list.append(' '.join([comp_opt, frag_opt]))
+
+ return opts_list
+
+def init_standard_table():
+ """ Initializes STANDARD_TABLE values.
+
+ STANDARD_TABLE's keys are pre-defined, and init_standard_table() assigns
+ the right value for each one of them.
+ """
+ opts_list = get_opts_list()
+
+ for key, value in zip(STANDARD_TABLE.keys(), opts_list):
+ STANDARD_TABLE[key] = value
+
+def generate_file(file_name, file_size):
+ """ Generates a file filled with 'x'.
+
+ Args:
+ file_name: the file's name.
+ file_size: the content's length and therefore the file size.
+ """
+ content = 'x' * file_size
+
+ file = open(file_name, 'w')
+ file.write(content)
+ file.close()
+
+def generate_sqfs_src_dir(build_dir):
+ """ Generates the source directory used to make the SquashFS images.
+
+ The source directory is generated at build_dir, and it has the following
+ structure:
+ sqfs_src_dir/
+ ├── empty-dir/
+ ├── f1000
+ ├── f4096
+ ├── f5096
+ ├── subdir/
+ │   └── subdir-file
+ └── sym -> subdir
+
+ 3 directories, 4 files
+
+ The files in the root dir. are prefixed with an 'f' followed by its size.
+
+ Args:
+ build_dir: u-boot's build-sandbox directory.
+ """
+
+ root = os.path.join(build_dir, SQFS_SRC_DIR)
+ # make root directory
+ os.makedirs(root)
+
+ # 4096: minimum block size
+ file_name = 'f4096'
+ generate_file(os.path.join(root, file_name), 4096)
+
+ # 5096: minimum block size + 1000 chars (fragment)
+ file_name = 'f5096'
+ generate_file(os.path.join(root, file_name), 5096)
+
+ # 1000: less than minimum block size (fragment only)
+ file_name = 'f1000'
+ generate_file(os.path.join(root, file_name), 1000)
+
+ # sub-directory with a single file inside
+ subdir_path = os.path.join(root, 'subdir')
+ os.makedirs(subdir_path)
+ generate_file(os.path.join(subdir_path, 'subdir-file'), 100)
+
+ # symlink (target: sub-directory)
+ os.symlink('subdir', os.path.join(root, 'sym'))
+
+ # empty directory
+ os.makedirs(os.path.join(root, 'empty-dir'))
+
+def mksquashfs(args):
+ """ Runs mksquashfs command.
+
+ Args:
+ args: mksquashfs options (e.g.: compression and fragmentation).
+ """
+ subprocess.run(['mksquashfs ' + args], shell=True, check=True,
+ stdout=subprocess.DEVNULL)
+
+def get_mksquashfs_version():
+ """ Parses the output of mksquashfs -version.
+
+ Returns:
+ mksquashfs's version as a float.
+ """
+ out = subprocess.run(['mksquashfs -version'], shell=True, check=True,
+ capture_output=True, text=True)
+ # 'out' is: mksquashfs version X (yyyy/mm/dd) ...
+ return out.stdout.split()[2].split('.')[0:2]
+
+def check_mksquashfs_version():
+ """ Checks if mksquashfs meets the required version. """
+
+ version = get_mksquashfs_version();
+ if int(version[0]) < 4 or int(version[0]) == 4 and int(version[1]) < 4 :
+ print('Error: mksquashfs is too old, required version: 4.4')
+ raise AssertionError
+
+def make_all_images(build_dir):
+ """ Makes the SquashFS images used in the test suite.
+
+ The image names and respective mksquashfs options are defined in STANDARD_TABLE
+ and EXTRA_TABLE. The destination is defined by 'build_dir'.
+
+ Args:
+ build_dir: u-boot's build-sandbox directory.
+ """
+
+ init_standard_table()
+ input_path = os.path.join(build_dir, SQFS_SRC_DIR)
+
+ # make squashfs images according to STANDARD_TABLE
+ for out, opts in zip(STANDARD_TABLE.keys(), STANDARD_TABLE.values()):
+ output_path = os.path.join(build_dir, out)
+ mksquashfs(' '.join([input_path, output_path, opts]))
+
+ # make squashfs images according to EXTRA_TABLE
+ for out, opts in zip(EXTRA_TABLE.keys(), EXTRA_TABLE.values()):
+ output_path = os.path.join(build_dir, out)
+ mksquashfs(' '.join([input_path, output_path, opts]))
+
+def clean_all_images(build_dir):
+ """ Deletes the SquashFS images at build_dir.
+
+ Args:
+ build_dir: u-boot's build-sandbox directory.
+ """
+
+ for image_name in STANDARD_TABLE:
+ image_path = os.path.join(build_dir, image_name)
+ os.remove(image_path)
+
+ for image_name in EXTRA_TABLE:
+ image_path = os.path.join(build_dir, image_name)
+ os.remove(image_path)
+
+def clean_sqfs_src_dir(build_dir):
+ """ Deletes the source directory at build_dir.
+
+ Args:
+ build_dir: u-boot's build-sandbox directory.
+ """
+ path = os.path.join(build_dir, SQFS_SRC_DIR)
+ shutil.rmtree(path)
diff --git a/test/py/tests/test_fs/test_squashfs/test_sqfs_load.py b/test/py/tests/test_fs/test_squashfs/test_sqfs_load.py
new file mode 100644
index 00000000000..6ec6ccec6c9
--- /dev/null
+++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_load.py
@@ -0,0 +1,154 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 Bootlin
+# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
+
+import os
+import subprocess
+import pytest
+
+from sqfs_common import SQFS_SRC_DIR, STANDARD_TABLE
+from sqfs_common import generate_sqfs_src_dir, make_all_images
+from sqfs_common import clean_sqfs_src_dir, clean_all_images
+from sqfs_common import check_mksquashfs_version
+
+@pytest.mark.requiredtool('md5sum')
+def original_md5sum(path):
+ """ Runs md5sum command.
+
+ Args:
+ path: path to original file.
+ Returns:
+ The original file's checksum as a string.
+ """
+
+ out = subprocess.run(['md5sum ' + path], shell=True, check=True,
+ capture_output=True, text=True)
+ checksum = out.stdout.split()[0]
+
+ return checksum
+
+def uboot_md5sum(u_boot_console, address, count):
+ """ Runs U-Boot's md5sum command.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ address: address where the file was loaded (e.g.: $kernel_addr_r).
+ count: file's size. It was named 'count' to match md5sum's respective
+ argument name.
+ Returns:
+ The checksum of the file loaded with sqfsload as a string.
+ """
+
+ out = u_boot_console.run_command('md5sum {} {}'.format(address, count))
+ checksum = out.split()[-1]
+
+ return checksum
+
+def sqfs_load_files(u_boot_console, files, sizes, address):
+ """ Loads files and asserts their checksums.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ files: list of files to be loaded.
+ sizes: the sizes of each file.
+ address: the address where the files should be loaded.
+ """
+ build_dir = u_boot_console.config.build_dir
+ for (file, size) in zip(files, sizes):
+ out = u_boot_console.run_command('sqfsload host 0 {} {}'.format(address, file))
+
+ # check if the right amount of bytes was read
+ assert size in out
+
+ # compare original file's checksum against u-boot's
+ u_boot_checksum = uboot_md5sum(u_boot_console, address, hex(int(size)))
+ original_file_path = os.path.join(build_dir, SQFS_SRC_DIR + '/' + file)
+ original_checksum = original_md5sum(original_file_path)
+ assert u_boot_checksum == original_checksum
+
+def sqfs_load_files_at_root(u_boot_console):
+ """ Calls sqfs_load_files passing the files at the SquashFS image's root.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+
+ files = ['f4096', 'f5096', 'f1000']
+ sizes = ['4096', '5096', '1000']
+ address = '$kernel_addr_r'
+ sqfs_load_files(u_boot_console, files, sizes, address)
+
+def sqfs_load_files_at_subdir(u_boot_console):
+ """ Calls sqfs_load_files passing the files at the SquashFS image's subdir.
+
+ This test checks if the path resolution works, since the file is not at the
+ root directory.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ files = ['subdir/subdir-file']
+ sizes = ['100']
+ address = '$kernel_addr_r'
+ sqfs_load_files(u_boot_console, files, sizes, address)
+
+def sqfs_load_non_existent_file(u_boot_console):
+ """ Calls sqfs_load_files passing an non-existent file to raise an error.
+
+ This test checks if the SquashFS support won't crash if it doesn't find the
+ specified file.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ address = '$kernel_addr_r'
+ file = 'non-existent'
+ out = u_boot_console.run_command('sqfsload host 0 {} {}'.format(address, file))
+ assert 'Failed to load' in out
+
+def sqfs_run_all_load_tests(u_boot_console):
+ """ Runs all the previously defined test cases.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ sqfs_load_files_at_root(u_boot_console)
+ sqfs_load_files_at_subdir(u_boot_console)
+ sqfs_load_non_existent_file(u_boot_console)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_fs_generic')
+@pytest.mark.buildconfigspec('cmd_squashfs')
+@pytest.mark.buildconfigspec('fs_squashfs')
+@pytest.mark.requiredtool('mksquashfs')
+def test_sqfs_load(u_boot_console):
+ """ Executes the sqfsload test suite.
+
+ First, it generates the SquashFS images, then it runs the test cases and
+ finally cleans the workspace. If an exception is raised, the workspace is
+ cleaned before exiting.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ build_dir = u_boot_console.config.build_dir
+
+ # setup test environment
+ check_mksquashfs_version()
+ generate_sqfs_src_dir(build_dir)
+ make_all_images(build_dir)
+
+ # run all tests for each image
+ for image in STANDARD_TABLE:
+ try:
+ image_path = os.path.join(build_dir, image)
+ u_boot_console.run_command('host bind 0 {}'.format(image_path))
+ sqfs_run_all_load_tests(u_boot_console)
+ except:
+ clean_all_images(build_dir)
+ clean_sqfs_src_dir(build_dir)
+ raise AssertionError
+
+ # clean test environment
+ clean_all_images(build_dir)
+ clean_sqfs_src_dir(build_dir)
diff --git a/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py b/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py
new file mode 100644
index 00000000000..a20a7d1a663
--- /dev/null
+++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py
@@ -0,0 +1,148 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 Bootlin
+# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
+
+import os
+import pytest
+
+from sqfs_common import STANDARD_TABLE
+from sqfs_common import generate_sqfs_src_dir, make_all_images
+from sqfs_common import clean_sqfs_src_dir, clean_all_images
+from sqfs_common import check_mksquashfs_version
+
+def sqfs_ls_at_root(u_boot_console):
+ """ Runs sqfsls at image's root.
+
+ This test checks if all the present files and directories were listed. Also,
+ it checks if passing the slash or not changes the output, which it shouldn't.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+
+ no_slash = u_boot_console.run_command('sqfsls host 0')
+ slash = u_boot_console.run_command('sqfsls host 0 /')
+ assert no_slash == slash
+
+ expected_lines = ['empty-dir/', '1000 f1000', '4096 f4096', '5096 f5096',
+ 'subdir/', '<SYM> sym', '4 file(s), 2 dir(s)']
+
+ output = u_boot_console.run_command('sqfsls host 0')
+ for line in expected_lines:
+ assert line in output
+
+def sqfs_ls_at_empty_dir(u_boot_console):
+ """ Runs sqfsls at an empty directory.
+
+ This tests checks if sqfsls will print anything other than the 'Empty directory'
+ message.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ assert u_boot_console.run_command('sqfsls host 0 empty-dir') == 'Empty directory.'
+
+def sqfs_ls_at_subdir(u_boot_console):
+ """ Runs sqfsls at the SquashFS image's subdir.
+
+ This test checks if the path resolution works, since the directory is not the
+ root.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ expected_lines = ['100 subdir-file', '1 file(s), 0 dir(s)']
+ output = u_boot_console.run_command('sqfsls host 0 subdir')
+ for line in expected_lines:
+ assert line in output
+
+def sqfs_ls_at_symlink(u_boot_console):
+ """ Runs sqfsls at a SquashFS image's symbolic link.
+
+ This test checks if the symbolic link's target resolution works.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ # since sym -> subdir, the following outputs must be equal
+ output = u_boot_console.run_command('sqfsls host 0 sym')
+ output_subdir = u_boot_console.run_command('sqfsls host 0 subdir')
+ assert output == output_subdir
+
+ expected_lines = ['100 subdir-file', '1 file(s), 0 dir(s)']
+ for line in expected_lines:
+ assert line in output
+
+def sqfs_ls_at_non_existent_dir(u_boot_console):
+ """ Runs sqfsls at a file and at a non-existent directory.
+
+ This test checks if the SquashFS support won't crash if it doesn't find the
+ specified directory or if it takes a file as an input instead of an actual
+ directory. In both cases, the output should be the same.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ out_non_existent = u_boot_console.run_command('sqfsls host 0 fff')
+ out_not_dir = u_boot_console.run_command('sqfsls host 0 f1000')
+ assert out_non_existent == out_not_dir
+ assert '** Cannot find directory. **' in out_non_existent
+
+def sqfs_run_all_ls_tests(u_boot_console):
+ """ Runs all the previously defined test cases.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ sqfs_ls_at_root(u_boot_console)
+ sqfs_ls_at_empty_dir(u_boot_console)
+ sqfs_ls_at_subdir(u_boot_console)
+ sqfs_ls_at_symlink(u_boot_console)
+ sqfs_ls_at_non_existent_dir(u_boot_console)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_fs_generic')
+@pytest.mark.buildconfigspec('cmd_squashfs')
+@pytest.mark.buildconfigspec('fs_squashfs')
+@pytest.mark.requiredtool('mksquashfs')
+@pytest.mark.singlethread
+def test_sqfs_ls(u_boot_console):
+ """ Executes the sqfsls test suite.
+
+ First, it generates the SquashFS images, then it runs the test cases and
+ finally cleans the workspace. If an exception is raised, the workspace is
+ cleaned before exiting.
+
+ Args:
+ u_boot_console: provides the means to interact with U-Boot's console.
+ """
+ build_dir = u_boot_console.config.build_dir
+
+ # If the EFI subsystem is enabled and initialized, EFI subsystem tries to
+ # add EFI boot option when the new disk is detected. If there is no EFI
+ # System Partition exists, EFI subsystem outputs error messages and
+ # it ends up with test failure.
+ # Restart U-Boot to clear the previous state.
+ # TODO: Ideally EFI test cases need to be fixed, but it will
+ # increase the number of system reset.
+ u_boot_console.restart_uboot()
+
+ # setup test environment
+ check_mksquashfs_version()
+ generate_sqfs_src_dir(build_dir)
+ make_all_images(build_dir)
+
+ # run all tests for each image
+ for image in STANDARD_TABLE:
+ try:
+ image_path = os.path.join(build_dir, image)
+ u_boot_console.run_command('host bind 0 {}'.format(image_path))
+ sqfs_run_all_ls_tests(u_boot_console)
+ except:
+ clean_all_images(build_dir)
+ clean_sqfs_src_dir(build_dir)
+ raise AssertionError
+
+ # clean test environment
+ clean_all_images(build_dir)
+ clean_sqfs_src_dir(build_dir)
diff --git a/test/py/tests/test_fs/test_symlink.py b/test/py/tests/test_fs/test_symlink.py
new file mode 100644
index 00000000000..9ced101a294
--- /dev/null
+++ b/test/py/tests/test_fs/test_symlink.py
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2019, Texas Instrument
+# Author: Jean-Jacques Hiblot <jjhiblot@ti.com>
+#
+# U-Boot File System:symlink Test
+
+"""
+This test verifies unlink operation (deleting a file or a directory)
+on file system.
+"""
+
+import pytest
+import re
+from fstest_defs import *
+from fstest_helpers import assert_fs_integrity
+
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestSymlink(object):
+ def test_symlink1(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 1 - create a link. and follow it when reading
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s.link ' % (SMALL_FILE, SMALL_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s.link' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 4b - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink2(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 2 - create chained links
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 2 - create chained links'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s.link1 ' % (SMALL_FILE, SMALL_FILE),
+ 'ln host 0:0 /%s.link1 /SUBDIR/%s.link2' % (
+ SMALL_FILE, SMALL_FILE),
+ 'ln host 0:0 SUBDIR/%s.link2 /%s.link3' % (
+ SMALL_FILE, SMALL_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s.link3' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=100000' in ''.join(output))
+
+ # Test Case 4b - Read full 1MB of small file
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[0] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink3(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 3 - replace file/link with link
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ 'setenv filesize',
+ 'ln host 0:0 %s /%s ' % (MEDIUM_FILE, SMALL_FILE),
+ 'ln host 0:0 %s /%s.link ' % (MEDIUM_FILE, MEDIUM_FILE),
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=a00000' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'ln host 0:0 %s.link /%s ' % (MEDIUM_FILE, SMALL_FILE),
+ '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+ 'printenv filesize'])
+ assert('filesize=a00000' in ''.join(output))
+
+ output = u_boot_console.run_command_list([
+ 'md5sum %x $filesize' % ADDR,
+ 'setenv filesize'])
+ assert(md5val[1] in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_symlink4(self, u_boot_console, fs_obj_symlink):
+ """
+ Test Case 4 - create a broken link
+ """
+ fs_type, fs_img, md5val = fs_obj_symlink
+ with u_boot_console.log.section('Test Case 1 - create link and read'):
+
+ output = u_boot_console.run_command_list([
+ 'setenv filesize',
+ 'ln host 0:0 nowhere /link ',
+ ])
+ assert('' in ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sload host 0:0 %x /link' %
+ (fs_type, ADDR))
+ with u_boot_console.disable_check('error_notification'):
+ output = u_boot_console.run_command('printenv filesize')
+ assert('"filesize" not defined' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py
new file mode 100644
index 00000000000..97aafc63bb5
--- /dev/null
+++ b/test/py/tests/test_fs/test_unlink.py
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:unlink Test
+
+"""
+This test verifies unlink operation (deleting a file or a directory)
+on file system.
+"""
+
+import pytest
+from fstest_helpers import assert_fs_integrity
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.slow
+class TestUnlink(object):
+ def test_unlink1(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 1 - delete a file
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 1 - unlink (file)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir1/file1' % fs_type,
+ '%sls host 0:0 dir1/file1' % fs_type])
+ assert('' == ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir1/' % fs_type)
+ assert(not 'file1' in output)
+ assert('file2' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink2(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 2 - delete many files
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 2 - unlink (many)'):
+ output = u_boot_console.run_command('host bind 0 %s' % fs_img)
+
+ for i in range(0, 20):
+ output = u_boot_console.run_command_list([
+ '%srm host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i),
+ '%sls host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i)])
+ assert('' == ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 dir2' % fs_type)
+ assert('0 file(s), 2 dir(s)' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink3(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 3 - trying to delete a non-existing file should fail
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 3 - unlink (non-existing)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir1/nofile' % fs_type])
+ assert('nofile: doesn\'t exist' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink4(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 4 - delete an empty directory
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 4 - unlink (directory)'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir4' % fs_type])
+ assert('' == ''.join(output))
+
+ output = u_boot_console.run_command(
+ '%sls host 0:0 /' % fs_type)
+ assert(not 'dir4' in output)
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink5(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 5 - trying to deleting a non-empty directory ".."
+ should fail
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 5 - unlink ("non-empty directory")'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir5' % fs_type])
+ assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink6(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 6 - trying to deleting a "." should fail
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 6 - unlink (".")'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir5/.' % fs_type])
+ assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)
+
+ def test_unlink7(self, u_boot_console, fs_obj_unlink):
+ """
+ Test Case 7 - trying to deleting a ".." should fail
+ """
+ fs_type,fs_img = fs_obj_unlink
+ with u_boot_console.log.section('Test Case 7 - unlink ("..")'):
+ output = u_boot_console.run_command_list([
+ 'host bind 0 %s' % fs_img,
+ '%srm host 0:0 dir5/..' % fs_type])
+ assert('directory is not empty' in ''.join(output))
+ assert_fs_integrity(fs_type, fs_img)