1# SPDX-License-Identifier:      GPL-2.0+
2# Copyright (c) 2018, Linaro Limited
3# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
4
5import os
6import os.path
7import pytest
8import re
9from subprocess import call, check_call, check_output, CalledProcessError
10from fstest_defs import *
11# pylint: disable=E0611
12from tests import fs_helper
13
14supported_fs_basic = ['fat16', 'fat32', 'exfat', 'ext4', 'fs_generic']
15supported_fs_ext = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
16supported_fs_fat = ['fat12', 'fat16']
17supported_fs_mkdir = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
18supported_fs_unlink = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
19supported_fs_symlink = ['ext4']
20supported_fs_rename = ['fat12', 'fat16', 'fat32', 'exfat', 'fs_generic']
21
22#
23# Filesystem test specific setup
24#
25def pytest_addoption(parser):
26    """Enable --fs-type option.
27
28    See pytest_configure() about how it works.
29
30    Args:
31        parser: Pytest command-line parser.
32
33    Returns:
34        Nothing.
35    """
36    parser.addoption('--fs-type', action='append', default=None,
37        help='Targeting Filesystem Types')
38
39def pytest_configure(config):
40    """Restrict a file system(s) to be tested.
41
42    A file system explicitly named with --fs-type option is selected
43    if it belongs to a default supported_fs_xxx list.
44    Multiple options can be specified.
45
46    Args:
47        config: Pytest configuration.
48
49    Returns:
50        Nothing.
51    """
52    global supported_fs_basic
53    global supported_fs_ext
54    global supported_fs_fat
55    global supported_fs_mkdir
56    global supported_fs_unlink
57    global supported_fs_symlink
58    global supported_fs_rename
59
60    def intersect(listA, listB):
61        return  [x for x in listA if x in listB]
62
63    supported_fs = config.getoption('fs_type')
64    if supported_fs:
65        print('*** FS TYPE modified: %s' % supported_fs)
66        supported_fs_basic =  intersect(supported_fs, supported_fs_basic)
67        supported_fs_ext =  intersect(supported_fs, supported_fs_ext)
68        supported_fs_fat =  intersect(supported_fs, supported_fs_fat)
69        supported_fs_mkdir =  intersect(supported_fs, supported_fs_mkdir)
70        supported_fs_unlink =  intersect(supported_fs, supported_fs_unlink)
71        supported_fs_symlink =  intersect(supported_fs, supported_fs_symlink)
72        supported_fs_rename =  intersect(supported_fs, supported_fs_rename)
73
74def pytest_generate_tests(metafunc):
75    """Parametrize fixtures, fs_obj_xxx
76
77    Each fixture will be parametrized with a corresponding support_fs_xxx
78    list.
79
80    Args:
81        metafunc: Pytest test function.
82
83    Returns:
84        Nothing.
85    """
86    if 'fs_obj_basic' in metafunc.fixturenames:
87        metafunc.parametrize('fs_obj_basic', supported_fs_basic,
88            indirect=True, scope='module')
89    if 'fs_obj_ext' in metafunc.fixturenames:
90        metafunc.parametrize('fs_obj_ext', supported_fs_ext,
91            indirect=True, scope='module')
92    if 'fs_obj_fat' in metafunc.fixturenames:
93        metafunc.parametrize('fs_obj_fat', supported_fs_fat,
94            indirect=True, scope='module')
95    if 'fs_obj_mkdir' in metafunc.fixturenames:
96        metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir,
97            indirect=True, scope='module')
98    if 'fs_obj_unlink' in metafunc.fixturenames:
99        metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
100            indirect=True, scope='module')
101    if 'fs_obj_symlink' in metafunc.fixturenames:
102        metafunc.parametrize('fs_obj_symlink', supported_fs_symlink,
103            indirect=True, scope='module')
104    if 'fs_obj_rename' in metafunc.fixturenames:
105        metafunc.parametrize('fs_obj_rename', supported_fs_rename,
106            indirect=True, scope='module')
107
108#
109# Helper functions
110#
111def fstype_to_prefix(fs_type):
112    """Convert a file system type to an U-Boot command prefix
113
114    Args:
115        fs_type: File system type.
116
117    Return:
118        A corresponding command prefix for file system type.
119    """
120    if fs_type == 'fs_generic' or fs_type == 'exfat':
121        return ''
122    elif re.match('fat', fs_type):
123        return 'fat'
124    else:
125        return fs_type
126
127def fstype_to_ubname(fs_type):
128    """Convert a file system type to an U-Boot specific string
129
130    A generated string can be used as part of file system related commands
131    or a config name in u-boot. Currently fat16 and fat32 are handled
132    specifically.
133
134    Args:
135        fs_type: File system type.
136
137    Return:
138        A corresponding string for file system type.
139    """
140    if re.match('fat', fs_type):
141        return 'fat'
142    else:
143        return fs_type
144
145def check_ubconfig(config, fs_type):
146    """Check whether a file system is enabled in u-boot configuration.
147
148    This function is assumed to be called in a fixture function so that
149    the whole test cases will be skipped if a given file system is not
150    enabled.
151
152    Args:
153        fs_type: File system type.
154
155    Return:
156        Nothing.
157    """
158    if fs_type == 'exfat' and not config.buildconfig.get('config_fs_%s' % fs_type, None):
159        pytest.skip('.config feature "FS_%s" not enabled' % fs_type.upper())
160    if fs_type != 'exfat' and not config.buildconfig.get('config_cmd_%s' % fs_type, None):
161        pytest.skip('.config feature "CMD_%s" not enabled' % fs_type.upper())
162    if fs_type == 'fs_generic' or fs_type == 'exfat':
163        return
164    if not config.buildconfig.get('config_%s_write' % fs_type, None):
165        pytest.skip('.config feature "%s_WRITE" not enabled'
166        % fs_type.upper())
167
168# from test/py/conftest.py
169def tool_is_in_path(tool):
170    """Check whether a given command is available on host.
171
172    Args:
173        tool: Command name.
174
175    Return:
176        True if available, False if not.
177    """
178    for path in os.environ['PATH'].split(os.pathsep):
179        fn = os.path.join(path, tool)
180        if os.path.isfile(fn) and os.access(fn, os.X_OK):
181            return True
182    return False
183
184#
185# Fixture for basic fs test
186#     derived from test/fs/fs-test.sh
187#
188@pytest.fixture()
189def fs_obj_basic(request, u_boot_config):
190    """Set up a file system to be used in basic fs test.
191
192    Args:
193        request: Pytest request object.
194	u_boot_config: U-Boot configuration.
195
196    Return:
197        A fixture for basic fs test, i.e. a triplet of file system type,
198        volume file name and  a list of MD5 hashes.
199    """
200    fs_type = request.param
201    fs_cmd_prefix = fstype_to_prefix(fs_type)
202    fs_cmd_write = 'save' if fs_type == 'fs_generic' or fs_type == 'exfat' else 'write'
203    fs_img = ''
204
205    fs_ubtype = fstype_to_ubname(fs_type)
206    check_ubconfig(u_boot_config, fs_ubtype)
207
208    scratch_dir = u_boot_config.persistent_data_dir + '/scratch'
209
210    small_file = scratch_dir + '/' + SMALL_FILE
211    big_file = scratch_dir + '/' + BIG_FILE
212
213    try:
214        check_call('mkdir -p %s' % scratch_dir, shell=True)
215    except CalledProcessError as err:
216        pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
217        call('rm -f %s' % fs_img, shell=True)
218        return
219
220    try:
221        # Create a subdirectory.
222        check_call('mkdir %s/SUBDIR' % scratch_dir, shell=True)
223
224        # Create big file in this image.
225        # Note that we work only on the start 1MB, couple MBs in the 2GB range
226        # and the last 1 MB of the huge 2.5GB file.
227        # So, just put random values only in those areas.
228        check_call('dd if=/dev/urandom of=%s bs=1M count=1'
229	    % big_file, shell=True)
230        check_call('dd if=/dev/urandom of=%s bs=1M count=2 seek=2047'
231            % big_file, shell=True)
232        check_call('dd if=/dev/urandom of=%s bs=1M count=1 seek=2499'
233            % big_file, shell=True)
234
235        # Create a small file in this image.
236        check_call('dd if=/dev/urandom of=%s bs=1M count=1'
237	    % small_file, shell=True)
238
239        # Delete the small file copies which possibly are written as part of a
240        # previous test.
241        # check_call('rm -f "%s.w"' % MB1, shell=True)
242        # check_call('rm -f "%s.w2"' % MB1, shell=True)
243
244        # Generate the md5sums of reads that we will test against small file
245        out = check_output(
246            'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
247	    % small_file, shell=True).decode()
248        md5val = [ out.split()[0] ]
249
250        # Generate the md5sums of reads that we will test against big file
251        # One from beginning of file.
252        out = check_output(
253            'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
254	    % big_file, shell=True).decode()
255        md5val.append(out.split()[0])
256
257        # One from end of file.
258        out = check_output(
259            'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum'
260	    % big_file, shell=True).decode()
261        md5val.append(out.split()[0])
262
263        # One from the last 1MB chunk of 2GB
264        out = check_output(
265            'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum'
266	    % big_file, shell=True).decode()
267        md5val.append(out.split()[0])
268
269        # One from the start 1MB chunk from 2GB
270        out = check_output(
271            'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum'
272	    % big_file, shell=True).decode()
273        md5val.append(out.split()[0])
274
275        # One 1MB chunk crossing the 2GB boundary
276        out = check_output(
277            'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum'
278	    % big_file, shell=True).decode()
279        md5val.append(out.split()[0])
280
281        try:
282            # 3GiB volume
283            fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB', scratch_dir)
284        except CalledProcessError as err:
285            pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
286            return
287
288    except CalledProcessError as err:
289        pytest.skip('Setup failed for filesystem: ' + fs_type + '. {}'.format(err))
290        return
291    else:
292        yield [fs_ubtype, fs_cmd_prefix, fs_cmd_write, fs_img, md5val]
293    finally:
294        call('rm -rf %s' % scratch_dir, shell=True)
295        call('rm -f %s' % fs_img, shell=True)
296
297#
298# Fixture for extended fs test
299#
300@pytest.fixture()
301def fs_obj_ext(request, u_boot_config):
302    """Set up a file system to be used in extended fs test.
303
304    Args:
305        request: Pytest request object.
306	u_boot_config: U-Boot configuration.
307
308    Return:
309        A fixture for extended fs test, i.e. a triplet of file system type,
310        volume file name and  a list of MD5 hashes.
311    """
312    fs_type = request.param
313    fs_cmd_prefix = fstype_to_prefix(fs_type)
314    fs_cmd_write = 'save' if fs_type == 'fs_generic' or fs_type == 'exfat' else 'write'
315    fs_img = ''
316
317    fs_ubtype = fstype_to_ubname(fs_type)
318    check_ubconfig(u_boot_config, fs_ubtype)
319
320    scratch_dir = u_boot_config.persistent_data_dir + '/scratch'
321
322    min_file = scratch_dir + '/' + MIN_FILE
323    tmp_file = scratch_dir + '/tmpfile'
324
325    try:
326        check_call('mkdir -p %s' % scratch_dir, shell=True)
327    except CalledProcessError as err:
328        pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
329        call('rm -f %s' % fs_img, shell=True)
330        return
331
332    try:
333        # Create a test directory
334        check_call('mkdir %s/dir1' % scratch_dir, shell=True)
335
336        # Create a small file and calculate md5
337        check_call('dd if=/dev/urandom of=%s bs=1K count=20'
338            % min_file, shell=True)
339        out = check_output(
340            'dd if=%s bs=1K 2> /dev/null | md5sum'
341            % min_file, shell=True).decode()
342        md5val = [ out.split()[0] ]
343
344        # Calculate md5sum of Test Case 4
345        check_call('dd if=%s of=%s bs=1K count=20'
346            % (min_file, tmp_file), shell=True)
347        check_call('dd if=%s of=%s bs=1K seek=5 count=20'
348            % (min_file, tmp_file), shell=True)
349        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
350            % tmp_file, shell=True).decode()
351        md5val.append(out.split()[0])
352
353        # Calculate md5sum of Test Case 5
354        check_call('dd if=%s of=%s bs=1K count=20'
355            % (min_file, tmp_file), shell=True)
356        check_call('dd if=%s of=%s bs=1K seek=5 count=5'
357            % (min_file, tmp_file), shell=True)
358        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
359            % tmp_file, shell=True).decode()
360        md5val.append(out.split()[0])
361
362        # Calculate md5sum of Test Case 7
363        check_call('dd if=%s of=%s bs=1K count=20'
364            % (min_file, tmp_file), shell=True)
365        check_call('dd if=%s of=%s bs=1K seek=20 count=20'
366            % (min_file, tmp_file), shell=True)
367        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
368            % tmp_file, shell=True).decode()
369        md5val.append(out.split()[0])
370
371        check_call('rm %s' % tmp_file, shell=True)
372
373        try:
374            # 128MiB volume
375            fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB', scratch_dir)
376        except CalledProcessError as err:
377            pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
378            return
379
380    except CalledProcessError:
381        pytest.skip('Setup failed for filesystem: ' + fs_type)
382        return
383    else:
384        yield [fs_ubtype, fs_cmd_prefix, fs_cmd_write, fs_img, md5val]
385    finally:
386        call('rm -rf %s' % scratch_dir, shell=True)
387        call('rm -f %s' % fs_img, shell=True)
388
389#
390# Fixture for mkdir test
391#
392@pytest.fixture()
393def fs_obj_mkdir(request, u_boot_config):
394    """Set up a file system to be used in mkdir test.
395
396    Args:
397        request: Pytest request object.
398	u_boot_config: U-Boot configuration.
399
400    Return:
401        A fixture for mkdir test, i.e. a duplet of file system type and
402        volume file name.
403    """
404    fs_type = request.param
405    fs_cmd_prefix = fstype_to_prefix(fs_type)
406    fs_img = ''
407
408    fs_ubtype = fstype_to_ubname(fs_type)
409    check_ubconfig(u_boot_config, fs_ubtype)
410
411    try:
412        # 128MiB volume
413        fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB', None)
414    except:
415        pytest.skip('Setup failed for filesystem: ' + fs_type)
416        return
417    else:
418        yield [fs_ubtype, fs_cmd_prefix, fs_img]
419    call('rm -f %s' % fs_img, shell=True)
420
421#
422# Fixture for unlink test
423#
424@pytest.fixture()
425def fs_obj_unlink(request, u_boot_config):
426    """Set up a file system to be used in unlink test.
427
428    Args:
429        request: Pytest request object.
430	u_boot_config: U-Boot configuration.
431
432    Return:
433        A fixture for unlink test, i.e. a duplet of file system type and
434        volume file name.
435    """
436    fs_type = request.param
437    fs_cmd_prefix = fstype_to_prefix(fs_type)
438    fs_img = ''
439
440    fs_ubtype = fstype_to_ubname(fs_type)
441    check_ubconfig(u_boot_config, fs_ubtype)
442
443    scratch_dir = u_boot_config.persistent_data_dir + '/scratch'
444
445    try:
446        check_call('mkdir -p %s' % scratch_dir, shell=True)
447    except CalledProcessError as err:
448        pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
449        call('rm -f %s' % fs_img, shell=True)
450        return
451
452    try:
453        # Test Case 1 & 3
454        check_call('mkdir %s/dir1' % scratch_dir, shell=True)
455        check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1'
456                                    % scratch_dir, shell=True)
457        check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1'
458                                    % scratch_dir, shell=True)
459
460        # Test Case 2
461        check_call('mkdir %s/dir2' % scratch_dir, shell=True)
462        for i in range(0, 20):
463            check_call('mkdir %s/dir2/0123456789abcdef%02x'
464                                    % (scratch_dir, i), shell=True)
465
466        # Test Case 4
467        check_call('mkdir %s/dir4' % scratch_dir, shell=True)
468
469        # Test Case 5, 6 & 7
470        check_call('mkdir %s/dir5' % scratch_dir, shell=True)
471        check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1'
472                                    % scratch_dir, shell=True)
473
474        try:
475            # 128MiB volume
476            fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB', scratch_dir)
477        except CalledProcessError as err:
478            pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
479            return
480
481    except CalledProcessError:
482        pytest.skip('Setup failed for filesystem: ' + fs_type)
483        return
484    else:
485        yield [fs_ubtype, fs_cmd_prefix, fs_img]
486    finally:
487        call('rm -rf %s' % scratch_dir, shell=True)
488        call('rm -f %s' % fs_img, shell=True)
489
490#
491# Fixture for symlink fs test
492#
493@pytest.fixture()
494def fs_obj_symlink(request, u_boot_config):
495    """Set up a file system to be used in symlink fs test.
496
497    Args:
498        request: Pytest request object.
499        u_boot_config: U-Boot configuration.
500
501    Return:
502        A fixture for basic fs test, i.e. a triplet of file system type,
503        volume file name and  a list of MD5 hashes.
504    """
505    fs_type = request.param
506    fs_img = ''
507
508    fs_ubtype = fstype_to_ubname(fs_type)
509    check_ubconfig(u_boot_config, fs_ubtype)
510
511    scratch_dir = u_boot_config.persistent_data_dir + '/scratch'
512
513    small_file = scratch_dir + '/' + SMALL_FILE
514    medium_file = scratch_dir + '/' + MEDIUM_FILE
515
516    try:
517        check_call('mkdir -p %s' % scratch_dir, shell=True)
518    except CalledProcessError as err:
519        pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
520        call('rm -f %s' % fs_img, shell=True)
521        return
522
523    try:
524        # Create a subdirectory.
525        check_call('mkdir %s/SUBDIR' % scratch_dir, shell=True)
526
527        # Create a small file in this image.
528        check_call('dd if=/dev/urandom of=%s bs=1M count=1'
529                   % small_file, shell=True)
530
531        # Create a medium file in this image.
532        check_call('dd if=/dev/urandom of=%s bs=10M count=1'
533                   % medium_file, shell=True)
534
535        # Generate the md5sums of reads that we will test against small file
536        out = check_output(
537            'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
538            % small_file, shell=True).decode()
539        md5val = [out.split()[0]]
540        out = check_output(
541            'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum'
542            % medium_file, shell=True).decode()
543        md5val.extend([out.split()[0]])
544
545        try:
546            # 1GiB volume
547            fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x40000000, '1GB', scratch_dir)
548        except CalledProcessError as err:
549            pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
550            return
551
552    except CalledProcessError:
553        pytest.skip('Setup failed for filesystem: ' + fs_type)
554        return
555    else:
556        yield [fs_ubtype, fs_img, md5val]
557    finally:
558        call('rm -rf %s' % scratch_dir, shell=True)
559        call('rm -f %s' % fs_img, shell=True)
560
561#
562# Fixture for rename test
563#
564@pytest.fixture()
565def fs_obj_rename(request, u_boot_config):
566    """Set up a file system to be used in rename tests.
567
568    Args:
569        request: Pytest request object.
570        u_boot_config: U-Boot configuration.
571
572    Return:
573        A fixture for rename tests, i.e. a triplet of file system type,
574        volume file name, and dictionary of test identifier and md5val.
575    """
576    def new_rand_file(path):
577        check_call('dd if=/dev/urandom of=%s bs=1K count=1' % path, shell=True)
578
579    def file_hash(path):
580        out = check_output(
581            'dd if=%s bs=1K skip=0 count=1 2> /dev/null | md5sum' % path,
582            shell=True
583        )
584        return out.decode().split()[0]
585
586    fs_type = request.param
587    fs_img = ''
588
589    fs_ubtype = fstype_to_ubname(fs_type)
590    check_ubconfig(u_boot_config, fs_ubtype)
591
592    mount_dir = u_boot_config.persistent_data_dir + '/scratch'
593
594    try:
595        check_call('mkdir -p %s' % mount_dir, shell=True)
596    except CalledProcessError as err:
597        pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err))
598        call('rm -f %s' % fs_img, shell=True)
599        return
600
601    try:
602        md5val = {}
603        # Test Case 1
604        check_call('mkdir %s/test1' % mount_dir, shell=True)
605        new_rand_file('%s/test1/file1' % mount_dir)
606        md5val['test1'] = file_hash('%s/test1/file1' % mount_dir)
607
608        # Test Case 2
609        check_call('mkdir %s/test2' % mount_dir, shell=True)
610        new_rand_file('%s/test2/file1' % mount_dir)
611        new_rand_file('%s/test2/file_exist' % mount_dir)
612        md5val['test2'] = file_hash('%s/test2/file1' % mount_dir)
613
614        # Test Case 3
615        check_call('mkdir -p %s/test3/dir1' % mount_dir, shell=True)
616        new_rand_file('%s/test3/dir1/file1' % mount_dir)
617        md5val['test3'] = file_hash('%s/test3/dir1/file1' % mount_dir)
618
619        # Test Case 4
620        check_call('mkdir -p %s/test4/dir1' % mount_dir, shell=True)
621        check_call('mkdir -p %s/test4/dir2/dir1' % mount_dir, shell=True)
622        new_rand_file('%s/test4/dir1/file1' % mount_dir)
623        md5val['test4'] = file_hash('%s/test4/dir1/file1' % mount_dir)
624
625        # Test Case 5
626        check_call('mkdir -p %s/test5/dir1' % mount_dir, shell=True)
627        new_rand_file('%s/test5/file2' % mount_dir)
628        md5val['test5'] = file_hash('%s/test5/file2' % mount_dir)
629
630        # Test Case 6
631        check_call('mkdir -p %s/test6/dir2/existing' % mount_dir, shell=True)
632        new_rand_file('%s/test6/existing' % mount_dir)
633        md5val['test6'] = file_hash('%s/test6/existing' % mount_dir)
634
635        # Test Case 7
636        check_call('mkdir -p %s/test7/dir1' % mount_dir, shell=True)
637        check_call('mkdir -p %s/test7/dir2/dir1' % mount_dir, shell=True)
638        new_rand_file('%s/test7/dir2/dir1/file1' % mount_dir)
639        md5val['test7'] = file_hash('%s/test7/dir2/dir1/file1' % mount_dir)
640
641        # Test Case 8
642        check_call('mkdir -p %s/test8/dir1' % mount_dir, shell=True)
643        new_rand_file('%s/test8/dir1/file1' % mount_dir)
644        md5val['test8'] = file_hash('%s/test8/dir1/file1' % mount_dir)
645
646        # Test Case 9
647        check_call('mkdir -p %s/test9/dir1/nested/inner' % mount_dir, shell=True)
648        new_rand_file('%s/test9/dir1/nested/inner/file1' % mount_dir)
649
650        # Test Case 10
651        check_call('mkdir -p %s/test10' % mount_dir, shell=True)
652        new_rand_file('%s/test10/file1' % mount_dir)
653        md5val['test10'] = file_hash('%s/test10/file1' % mount_dir)
654
655        # Test Case 11
656        check_call('mkdir -p %s/test11/dir1' % mount_dir, shell=True)
657        new_rand_file('%s/test11/dir1/file1' % mount_dir)
658        md5val['test11'] = file_hash('%s/test11/dir1/file1' % mount_dir)
659
660        try:
661            # 128MiB volume
662            fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB', mount_dir)
663        except CalledProcessError as err:
664            pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err))
665            return
666
667    except CalledProcessError:
668        pytest.skip('Setup failed for filesystem: ' + fs_type)
669        return
670    else:
671        yield [fs_ubtype, fs_img, md5val]
672    finally:
673        call('rm -rf %s' % mount_dir, shell=True)
674        call('rm -f %s' % fs_img, shell=True)
675
676#
677# Fixture for fat test
678#
679@pytest.fixture()
680def fs_obj_fat(request, u_boot_config):
681    """Set up a file system to be used in fat test.
682
683    Args:
684        request: Pytest request object.
685        u_boot_config: U-Boot configuration.
686
687    Return:
688        A fixture for fat test, i.e. a duplet of file system type and
689        volume file name.
690    """
691
692    # the maximum size of a FAT12 filesystem resulting in 4084 clusters
693    MAX_FAT12_SIZE = 261695 * 1024
694
695    # the minimum size of a FAT16 filesystem that can be created with
696    # mkfs.vfat resulting in 4087 clusters
697    MIN_FAT16_SIZE = 8208 * 1024
698
699    fs_type = request.param
700    fs_img = ''
701
702    fs_ubtype = fstype_to_ubname(fs_type)
703    check_ubconfig(u_boot_config, fs_ubtype)
704
705    fs_size = MAX_FAT12_SIZE if fs_type == 'fat12' else MIN_FAT16_SIZE
706
707    try:
708        # the volume size depends on the filesystem
709        fs_img = fs_helper.mk_fs(u_boot_config, fs_type, fs_size, f'{fs_size}', None, 1024)
710    except:
711        pytest.skip('Setup failed for filesystem: ' + fs_type)
712        return
713    else:
714        yield [fs_ubtype, fs_img]
715    call('rm -f %s' % fs_img, shell=True)
716