1# SPDX-License-Identifier: GPL-2.0
2# Copyright (C) 2020 Bootlin
3# Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
4
5import os
6import subprocess
7import pytest
8
9from sqfs_common import SQFS_SRC_DIR, STANDARD_TABLE
10from sqfs_common import generate_sqfs_src_dir, make_all_images
11from sqfs_common import clean_sqfs_src_dir, clean_all_images
12from sqfs_common import check_mksquashfs_version
13
14@pytest.mark.requiredtool('md5sum')
15def original_md5sum(path):
16    """ Runs md5sum command.
17
18    Args:
19        path: path to original file.
20    Returns:
21        The original file's checksum as a string.
22    """
23
24    out = subprocess.run(['md5sum ' + path], shell=True, check=True,
25                         capture_output=True, text=True)
26    checksum = out.stdout.split()[0]
27
28    return checksum
29
30def uboot_md5sum(u_boot_console, address, count):
31    """ Runs U-Boot's md5sum command.
32
33    Args:
34        u_boot_console: provides the means to interact with U-Boot's console.
35        address: address where the file was loaded (e.g.: $kernel_addr_r).
36        count: file's size. It was named 'count' to match md5sum's respective
37        argument name.
38    Returns:
39        The checksum of the file loaded with sqfsload as a string.
40    """
41
42    out = u_boot_console.run_command('md5sum {} {}'.format(address, count))
43    checksum = out.split()[-1]
44
45    return checksum
46
47def sqfs_load_files(u_boot_console, files, sizes, address):
48    """ Loads files and asserts their checksums.
49
50    Args:
51        u_boot_console: provides the means to interact with U-Boot's console.
52        files: list of files to be loaded.
53        sizes: the sizes of each file.
54        address: the address where the files should be loaded.
55    """
56    build_dir = u_boot_console.config.build_dir
57    for (file, size) in zip(files, sizes):
58        out = u_boot_console.run_command('sqfsload host 0 {} {}'.format(address, file))
59
60        # check if the right amount of bytes was read
61        assert size in out
62
63        # compare original file's checksum against u-boot's
64        u_boot_checksum = uboot_md5sum(u_boot_console, address, hex(int(size)))
65        original_file_path = os.path.join(build_dir, SQFS_SRC_DIR + '/' + file)
66        original_checksum = original_md5sum(original_file_path)
67        assert u_boot_checksum == original_checksum
68
69def sqfs_load_files_at_root(u_boot_console):
70    """ Calls sqfs_load_files passing the files at the SquashFS image's root.
71
72    Args:
73        u_boot_console: provides the means to interact with U-Boot's console.
74    """
75
76    files = ['f4096', 'f5096', 'f1000']
77    sizes = ['4096', '5096', '1000']
78    address = '$kernel_addr_r'
79    sqfs_load_files(u_boot_console, files, sizes, address)
80
81def sqfs_load_files_at_subdir(u_boot_console):
82    """ Calls sqfs_load_files passing the files at the SquashFS image's subdir.
83
84    This test checks if the path resolution works, since the file is not at the
85    root directory.
86
87    Args:
88        u_boot_console: provides the means to interact with U-Boot's console.
89    """
90    files = ['subdir/subdir-file']
91    sizes = ['100']
92    address = '$kernel_addr_r'
93    sqfs_load_files(u_boot_console, files, sizes, address)
94
95def sqfs_load_non_existent_file(u_boot_console):
96    """ Calls sqfs_load_files passing an non-existent file to raise an error.
97
98    This test checks if the SquashFS support won't crash if it doesn't find the
99    specified file.
100
101    Args:
102        u_boot_console: provides the means to interact with U-Boot's console.
103    """
104    address = '$kernel_addr_r'
105    file = 'non-existent'
106    out = u_boot_console.run_command('sqfsload host 0 {} {}'.format(address, file))
107    assert 'Failed to load' in out
108
109def sqfs_run_all_load_tests(u_boot_console):
110    """ Runs all the previously defined test cases.
111
112    Args:
113        u_boot_console: provides the means to interact with U-Boot's console.
114    """
115    sqfs_load_files_at_root(u_boot_console)
116    sqfs_load_files_at_subdir(u_boot_console)
117    sqfs_load_non_existent_file(u_boot_console)
118
119@pytest.mark.boardspec('sandbox')
120@pytest.mark.buildconfigspec('cmd_fs_generic')
121@pytest.mark.buildconfigspec('cmd_squashfs')
122@pytest.mark.buildconfigspec('fs_squashfs')
123@pytest.mark.requiredtool('mksquashfs')
124def test_sqfs_load(u_boot_console):
125    """ Executes the sqfsload test suite.
126
127    First, it generates the SquashFS images, then it runs the test cases and
128    finally cleans the workspace. If an exception is raised, the workspace is
129    cleaned before exiting.
130
131    Args:
132        u_boot_console: provides the means to interact with U-Boot's console.
133    """
134    build_dir = u_boot_console.config.build_dir
135
136    # setup test environment
137    check_mksquashfs_version()
138    generate_sqfs_src_dir(build_dir)
139    make_all_images(build_dir)
140
141    # run all tests for each image
142    for image in STANDARD_TABLE:
143        try:
144            image_path = os.path.join(build_dir, image)
145            u_boot_console.run_command('host bind 0 {}'.format(image_path))
146            sqfs_run_all_load_tests(u_boot_console)
147        except:
148            clean_all_images(build_dir)
149            clean_sqfs_src_dir(build_dir)
150            raise AssertionError
151
152    # clean test environment
153    clean_all_images(build_dir)
154    clean_sqfs_src_dir(build_dir)
155