aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-07-05 15:29:44 -0400
committerTom Rini <trini@konsulko.com>2021-07-05 15:29:44 -0400
commit1311dd37ecf476be041d0452d4ee38619aadd5de (patch)
tree5c48d348930efa23ec452673f2afafb9581e8eb9
parent6194b45a83bde42cd2f404123823e5b326702001 (diff)
parentb1c2102db1774686282474aee3c2dd06df92f175 (diff)
downloadu-boot-1311dd37ecf476be041d0452d4ee38619aadd5de.zip
u-boot-1311dd37ecf476be041d0452d4ee38619aadd5de.tar.gz
u-boot-1311dd37ecf476be041d0452d4ee38619aadd5de.tar.bz2
Merge branch '2021-07-01-update-CI-containers'
- General test.py improvements - Rewrite the squashfs tests - Update our CI container to Ubuntu 20.04 "focal" base. - Make some changes to the Azure yaml so that we can have more tests run there.
-rw-r--r--.azure-pipelines.yml19
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--cmd/nvedit_efi.c3
-rwxr-xr-xtest/nokia_rx51_test.sh2
-rw-r--r--test/py/tests/test_fs/conftest.py42
-rw-r--r--test/py/tests/test_fs/test_squashfs/sqfs_common.py257
-rw-r--r--test/py/tests/test_fs/test_squashfs/test_sqfs_load.py168
-rw-r--r--test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py140
-rw-r--r--test/py/u_boot_utils.py36
-rw-r--r--tools/docker/Dockerfile24
10 files changed, 547 insertions, 146 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 221e600..06c4a2f 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -2,7 +2,7 @@ variables:
windows_vm: vs2017-win2016
ubuntu_vm: ubuntu-18.04
macos_vm: macOS-10.15
- ci_runner_image: trini/u-boot-gitlab-ci-runner:bionic-20200807-02Sep2020
+ ci_runner_image: trini/u-boot-gitlab-ci-runner:focal-20210609-01Jul2021
# Add '-u 0' options for Azure pipelines, otherwise we get "permission
# denied" error when it tries to "useradd -m -u 1001 vsts_azpcontainer",
# since our $(ci_runner_image) user is not root.
@@ -318,7 +318,22 @@ jobs:
# as sandbox testing need create files like spi flash images, etc.
# (TODO: clean up this in the future)
chmod 777 .
- docker run -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/test.sh
+ # Filesystem tests need extra docker args to run
+ set --
+ if [[ "${TEST_PY_BD}" == "sandbox" ]]; then
+ # mount -o loop needs the loop devices
+ if modprobe loop; then
+ for d in $(find /dev -maxdepth 1 -name 'loop*'); do
+ set -- "$@" --device $d:$d
+ done
+ fi
+ # Needed for mount syscall (for guestmount as well)
+ set -- "$@" --cap-add SYS_ADMIN
+ # Default apparmor profile denies mounts
+ set -- "$@" --security-opt apparmor=unconfined
+ fi
+ # Some tests using libguestfs-tools need the fuse device to run
+ docker run "$@" --device /dev/fuse:/dev/fuse -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/test.sh
- job: build_the_world
displayName: 'Build the World'
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d072e83..94c7333 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@
# Grab our configured image. The source for this is found at:
# https://source.denx.de/u-boot/gitlab-ci-runner
-image: trini/u-boot-gitlab-ci-runner:bionic-20200807-02Sep2020
+image: trini/u-boot-gitlab-ci-runner:focal-20210609-01Jul2021
# We run some tests in different order, to catch some failures quicker.
stages:
diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c
index 094c0e8..d5e9382 100644
--- a/cmd/nvedit_efi.c
+++ b/cmd/nvedit_efi.c
@@ -241,6 +241,7 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const efi_guid_t *guid_p = NULL;
+ efi_guid_t guid;
bool verbose = true;
efi_status_t ret;
@@ -254,8 +255,6 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc,
for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
if (!strcmp(argv[0], "-guid")) {
- efi_guid_t guid;
-
if (argc == 1)
return CMD_RET_USAGE;
argc--;
diff --git a/test/nokia_rx51_test.sh b/test/nokia_rx51_test.sh
index ee45e8d..ff840c1 100755
--- a/test/nokia_rx51_test.sh
+++ b/test/nokia_rx51_test.sh
@@ -56,7 +56,7 @@ if ! test -f qemu-system-arm; then
test -d qemu-linaro || git clone https://git.linaro.org/qemu/qemu-linaro.git
cd qemu-linaro
git checkout 8f8d8e0796efe1a6f34cdd83fb798f3c41217ec1
- ./configure --enable-system --target-list=arm-softmmu --disable-sdl --disable-gtk --disable-curses --audio-drv-list= --audio-card-list= --disable-werror --disable-xen --disable-xen-pci-passthrough --disable-brlapi --disable-vnc --disable-curl --disable-slirp --disable-kvm --disable-user --disable-linux-user --disable-bsd-user --disable-guest-base --disable-uuid --disable-vde --disable-linux-aio --disable-cap-ng --disable-attr --disable-blobs --disable-docs --disable-spice --disable-libiscsi --disable-smartcard-nss --disable-usb-redir --disable-guest-agent --disable-seccomp --disable-glusterfs --disable-nptl --disable-fdt
+ ./configure --enable-system --target-list=arm-softmmu --python=/usr/bin/python2.7 --disable-sdl --disable-gtk --disable-curses --audio-drv-list= --audio-card-list= --disable-werror --disable-xen --disable-xen-pci-passthrough --disable-brlapi --disable-vnc --disable-curl --disable-slirp --disable-kvm --disable-user --disable-linux-user --disable-bsd-user --disable-guest-base --disable-uuid --disable-vde --disable-linux-aio --disable-cap-ng --disable-attr --disable-blobs --disable-docs --disable-spice --disable-libiscsi --disable-smartcard-nss --disable-usb-redir --disable-guest-agent --disable-seccomp --disable-glusterfs --disable-nptl --disable-fdt
make -j4
cd ..
ln -s qemu-linaro/arm-softmmu/qemu-system-arm .
diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
index 7325486..b638284 100644
--- a/test/py/tests/test_fs/conftest.py
+++ b/test/py/tests/test_fs/conftest.py
@@ -8,6 +8,7 @@ import pytest
import re
from subprocess import call, check_call, check_output, CalledProcessError
from fstest_defs import *
+import u_boot_utils as util
supported_fs_basic = ['fat16', 'fat32', 'ext4']
supported_fs_ext = ['fat16', 'fat32']
@@ -209,24 +210,23 @@ def mount_fs(fs_type, device, mount_point):
"""
global fuse_mounted
- fuse_mounted = False
try:
- if tool_is_in_path('guestmount'):
- fuse_mounted = True
- check_call('guestmount -a %s -m /dev/sda %s'
- % (device, mount_point), shell=True)
- else:
- 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)
+ check_call('guestmount --pid-file guestmount.pid -a %s -m /dev/sda %s'
+ % (device, mount_point), shell=True)
+ fuse_mounted = True
+ return
except CalledProcessError:
- raise
+ 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.
@@ -240,6 +240,16 @@ def umount_fs(mount_point):
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)
diff --git a/test/py/tests/test_fs/test_squashfs/sqfs_common.py b/test/py/tests/test_fs/test_squashfs/sqfs_common.py
index c96f92c..267c4b5 100644
--- a/test/py/tests/test_fs/test_squashfs/sqfs_common.py
+++ b/test/py/tests/test_fs/test_squashfs/sqfs_common.py
@@ -3,74 +3,203 @@
# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
import os
-import random
-import string
+import shutil
import subprocess
-def sqfs_get_random_letters(size):
- letters = []
- for i in range(0, size):
- letters.append(random.choice(string.ascii_letters))
+""" 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' : ''
+}
- return ''.join(letters)
+""" EXTRA_TABLE: Set this table's keys and values if you want to make squashfs
+images with your own customized options.
+"""
+EXTRA_TABLE = {}
-def sqfs_generate_file(path, size):
- content = sqfs_get_random_letters(size)
- file = open(path, "w")
+# 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()
-class Compression:
- def __init__(self, name, files, sizes, block_size = 4096):
- self.name = name
- self.files = files
- self.sizes = sizes
- self.mksquashfs_opts = " -b " + str(block_size) + " -comp " + self.name
-
- def add_opt(self, opt):
- self.mksquashfs_opts += " " + opt
-
- def gen_image(self, build_dir):
- src = os.path.join(build_dir, "sqfs_src/")
- os.mkdir(src)
- for (f, s) in zip(self.files, self.sizes):
- sqfs_generate_file(src + f, s)
-
- # the symbolic link always targets the first file
- os.symlink(self.files[0], src + "sym")
-
- sqfs_img = os.path.join(build_dir, "sqfs-" + self.name)
- i_o = src + " " + sqfs_img
- opts = self.mksquashfs_opts
- try:
- subprocess.run(["mksquashfs " + i_o + opts], shell = True, check = True)
- except:
- print("mksquashfs error. Compression type: " + self.name)
- raise RuntimeError
-
- def clean_source(self, build_dir):
- src = os.path.join(build_dir, "sqfs_src/")
- for f in self.files:
- os.remove(src + f)
- os.remove(src + "sym")
- os.rmdir(src)
-
- def cleanup(self, build_dir):
- self.clean_source(build_dir)
- sqfs_img = os.path.join(build_dir, "sqfs-" + self.name)
- os.remove(sqfs_img)
-
-files = ["blks_only", "blks_frag", "frag_only"]
-sizes = [4096, 5100, 100]
-gzip = Compression("gzip", files, sizes)
-zstd = Compression("zstd", files, sizes)
-lzo = Compression("lzo", files, sizes)
-
-# use fragment blocks for files larger than block_size
-gzip.add_opt("-always-use-fragments")
-zstd.add_opt("-always-use-fragments")
-
-# avoid fragments if lzo is used
-lzo.add_opt("-no-fragments")
-
-comp_opts = [gzip, zstd, lzo]
+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 float(out.stdout.split()[2])
+
+def check_mksquashfs_version():
+ """ Checks if mksquashfs meets the required version. """
+
+ required_version = 4.4
+ if get_mksquashfs_version() < required_version:
+ print('Error: mksquashfs is too old.')
+ print('Required version: {}'.format(required_version))
+ 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
index 9e90062..6ec6cce 100644
--- a/test/py/tests/test_fs/test_squashfs/test_sqfs_load.py
+++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_load.py
@@ -3,8 +3,118 @@
# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
import os
+import subprocess
import pytest
-from sqfs_common import *
+
+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')
@@ -12,35 +122,33 @@ from sqfs_common import *
@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
- command = "sqfsload host 0 $kernel_addr_r "
- for opt in comp_opts:
- # generate and load the squashfs image
+ # 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:
- opt.gen_image(build_dir)
- except RuntimeError:
- opt.clean_source(build_dir)
- # skip unsupported compression types
- continue
-
- path = os.path.join(build_dir, "sqfs-" + opt.name)
- output = u_boot_console.run_command("host bind 0 " + path)
-
- output = u_boot_console.run_command(command + "xxx")
- assert "File not found." in output
-
- for (f, s) in zip(opt.files, opt.sizes):
- try:
- output = u_boot_console.run_command(command + f)
- assert str(s) in output
- except:
- assert False
- opt.cleanup(build_dir)
-
- # test symbolic link
- output = u_boot_console.run_command(command + "sym")
- assert str(opt.sizes[0]) in output
-
- # remove generated files
- opt.cleanup(build_dir)
+ 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
index a0dca2e..9eb00d6 100644
--- a/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py
+++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py
@@ -4,7 +4,101 @@
import os
import pytest
-from sqfs_common import *
+
+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')
@@ -12,25 +106,33 @@ from sqfs_common import *
@pytest.mark.buildconfigspec('fs_squashfs')
@pytest.mark.requiredtool('mksquashfs')
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
- for opt in comp_opts:
- try:
- opt.gen_image(build_dir)
- except RuntimeError:
- opt.clean_source(build_dir)
- # skip unsupported compression types
- continue
- path = os.path.join(build_dir, "sqfs-" + opt.name)
- output = u_boot_console.run_command("host bind 0 " + path)
+ # 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:
- # list files in root directory
- output = u_boot_console.run_command("sqfsls host 0")
- assert str(len(opt.files) + 1) + " file(s), 0 dir(s)" in output
- assert "<SYM> sym" in output
- output = u_boot_console.run_command("sqfsls host 0 xxx")
- assert "** Cannot find directory. **" in output
+ 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:
- opt.cleanup(build_dir)
- assert False
- opt.cleanup(build_dir)
+ 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/u_boot_utils.py b/test/py/u_boot_utils.py
index 939d82e..e816c7f 100644
--- a/test/py/u_boot_utils.py
+++ b/test/py/u_boot_utils.py
@@ -8,6 +8,7 @@ import inspect
import os
import os.path
import pytest
+import signal
import sys
import time
import re
@@ -339,3 +340,38 @@ def crc32(u_boot_console, address, count):
assert m, 'CRC32 operation failed.'
return m.group(1)
+
+def waitpid(pid, timeout=60, kill=False):
+ """Wait a process to terminate by its PID
+
+ This is an alternative to a os.waitpid(pid, 0) call that works on
+ processes that aren't children of the python process.
+
+ Args:
+ pid: PID of a running process.
+ timeout: Time in seconds to wait.
+ kill: Whether to forcibly kill the process after timeout.
+
+ Returns:
+ True, if the process ended on its own.
+ False, if the process was killed by this function.
+
+ Raises:
+ TimeoutError, if the process is still running after timeout.
+ """
+ try:
+ for _ in range(timeout):
+ os.kill(pid, 0)
+ time.sleep(1)
+
+ if kill:
+ os.kill(pid, signal.SIGKILL)
+ return False
+
+ except ProcessLookupError:
+ return True
+
+ raise TimeoutError(
+ "Process with PID {} did not terminate after {} seconds."
+ .format(pid, timeout)
+ )
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index d2f0074..de0c6ce 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -2,7 +2,7 @@
# This Dockerfile is used to build an image containing basic stuff to be used
# to build U-Boot and run our test suites.
-FROM ubuntu:bionic-20200807
+FROM ubuntu:focal-20210609
MAINTAINER Tom Rini <trini@konsulko.com>
LABEL Description=" This image is for building U-Boot inside a container"
@@ -12,7 +12,7 @@ ENV DEBIAN_FRONTEND=noninteractive
# Add LLVM repository
RUN apt-get update && apt-get install -y gnupg2 wget xz-utils && rm -rf /var/lib/apt/lists/*
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-RUN echo deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main | tee /etc/apt/sources.list.d/llvm.list
+RUN echo deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main | tee /etc/apt/sources.list.d/llvm.list
# Manually install the kernel.org "Crosstool" based toolchains for gcc-7.3
RUN wget -O - https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/9.2.0/x86_64-gcc-9.2.0-nolibc-aarch64-linux.tar.xz | tar -C /opt -xJ
@@ -61,16 +61,17 @@ RUN apt-get update && apt-get install -y \
iasl \
imagemagick \
iputils-ping \
+ libgit2-dev \
libguestfs-tools \
- libisl15 \
liblz4-tool \
libpixman-1-dev \
- libpython-dev \
+ libpython3-dev \
libsdl1.2-dev \
libsdl2-dev \
libssl-dev \
libudev-dev \
libusb-1.0-0-dev \
+ linux-image-kvm \
lzma-alone \
lzop \
mount \
@@ -80,12 +81,13 @@ RUN apt-get update && apt-get install -y \
picocom \
parted \
pkg-config \
- python \
- python-dev \
- python-pip \
- python-virtualenv \
+ python-is-python3 \
+ python2.7 \
+ python3 \
+ python3-dev \
python3-pip \
python3-sphinx \
+ python3-virtualenv \
rpm2cpio \
sbsigntool \
sloccount \
@@ -99,12 +101,12 @@ RUN apt-get update && apt-get install -y \
zip \
&& rm -rf /var/lib/apt/lists/*
+# Make kernels readable for libguestfs tools to work correctly
+RUN chmod +r /boot/vmlinu*
+
# Manually install libmpfr4 for the toolchains
RUN wget http://mirrors.kernel.org/ubuntu/pool/main/m/mpfr4/libmpfr4_3.1.4-1_amd64.deb && dpkg -i libmpfr4_3.1.4-1_amd64.deb && rm libmpfr4_3.1.4-1_amd64.deb
-# Manually install a new enough version of efitools (must be v1.5.2 or later)
-RUN wget http://mirrors.kernel.org/ubuntu/pool/universe/e/efitools/efitools_1.8.1-0ubuntu2_amd64.deb && sudo dpkg -i efitools_1.8.1-0ubuntu2_amd64.deb && rm efitools_1.8.1-0ubuntu2_amd64.deb
-
# Manually install a new enough version of sbsigntools (must be v0.9.4 or later)
RUN git clone https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git /tmp/sbsigntools && \
cd /tmp/sbsigntools && \