
Hi,
On 5 November 2016 at 10:45, Stefan Brüns stefan.bruens@rwth-aachen.de wrote:
The following checks are currently implemented:
- listing a directory
- verifying size of a file
- veryfying md5sum for a file region
- reading the beginning of a file
Signed-off-by: Stefan Brüns stefan.bruens@rwth-aachen.de
test/py/tests/test_fs.py | 298 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 test/py/tests/test_fs.py
diff --git a/test/py/tests/test_fs.py b/test/py/tests/test_fs.py new file mode 100644 index 0000000..5ac91e4 --- /dev/null +++ b/test/py/tests/test_fs.py @@ -0,0 +1,298 @@ +# Copyright (c) 2016, Stefan Bruens stefan.bruens@rwth-aachen.de +# +# SPDX-License-Identifier: GPL-2.0
+# Test U-Boot's filesystem implementations
Can you add a few details here about what this tests?
+import hashlib +import pytest +import os +import random +import re +import u_boot_utils as util
+mkfs_opts = {
"fat" :'-t vfat',
"ext4" : '-t ext4 -F',
Can you please use a single quote unless you can't? That is the style used in U-Boot.
+}
+fs_commands = {
"fat" : {
'listcmd' : 'ls',
'readcmd' : 'load',
'sizecmd' : 'size',
'writecmd' : 'size',
},
"ext4" : {
'listcmd' : 'ls',
'readcmd' : 'load',
'sizecmd' : 'size',
'writecmd' : 'size',
},
+}
+cmd_parameters = {
"hostfs" : {
'prefix' : 'host ',
'interface' : 'hostfs -',
},
"generic" : {
'prefix' : '',
'interface' : 'host 0:0',
},
+}
+files = {
- "empty.file" : [(0, 0)],
- "1MB.file" : [(0, 1e6)],
- "1MB.sparse.file" : [(1e6-1, 1e6)],
+}
- # "2_5GB.sparse.file" : [(0, 1e6), (1e9, 1e9+1e6), (2.5e9-1e6, 2.5e9)],
What is that line for?
+@pytest.fixture(scope="session") +def prereq_commands():
- from distutils.spawn import find_executable
Why not import this at the top of the file?
- for command in ["mkfs", "mount", "umount"]:
if find_executable(command) is None:
pytest.skip('Filesystem tests, "{0}" not in PATH'.format(command))
+class FsImage:
- def __init__(self, fstype, imagename, mountpath):
Please add comments as to what these params are.
self.fstype = fstype
self.imagename = imagename
self.mountpath = mountpath
self.md5s = {}
with open(self.imagename, 'w') as fd:
fd.truncate(0)
fd.seek(3e9)
fd.write(bytes([0]))
- def mkfs(self, log):
mkfsopts = mkfs_opts.get(self.fstype)
util.run_and_log(log,
'mkfs {0} {1}'.format(mkfsopts, self.imagename))
- def create_file(self, log, filename):
Please add a short comment on each non-function describing what it does and what the args are (and return value if any).
md5sums = []
with open(self.mountpath + "/" + filename, 'w') as fd:
I think this is better as os.path.join(self.mountpath, filename)
for stride in files[filename]:
length = int(stride[1] - stride[0])
data = bytearray(random.getrandbits(8) for _ in xrange(length))
md5 = hashlib.md5(data).hexdigest()
md5sums.append(md5)
log.info("{0}: write {1} bytes @ {2} : {3}".format(
filename, int(stride[1] - stride[0]),
int(stride[0]), md5))
fd.seek(stride[0])
fd.write(data);
self.md5s[filename] = md5sums
- def create_files(self, log):
with log.section("Create initial files"):
for filename in files:
self.create_file(log, filename)
log.info("Created test files in {0}".format(self.mountpath))
util.run_and_log(log, 'ls -la {0}'.format(self.mountpath))
util.run_and_log(log, 'sync {0}'.format(self.mountpath))
- def mount(self, log):
if not os.path.exists(self.mountpath):
os.mkdir(self.mountpath)
log.info("Mounting {0} at {1}".format(self.imagename, self.mountpath))
if self.fstype == "ext4":
cmd = 'sudo -n mount -o loop,rw {0} {1}'.format(self.imagename, self.mountpath)
else:
cmd = 'sudo -n mount -o loop,rw,umask=000 {0} {1}'.format(self.imagename, self.mountpath)
util.run_and_log(log, cmd)
if self.fstype == "ext4":
cmd = 'sudo -n chmod og+rw {0}'.format(self.mountpath)
return util.run_and_log(log, cmd)
- def unmount(self, log):
log.info("Unmounting {0}".format(self.imagename))
cmd = 'sudo -n umount -l {0}'.format(self.mountpath)
util.run_and_log(log, cmd, ignore_errors=True)
+@pytest.fixture(scope="module", params=["fat", "ext4"]) +def fsimage(prereq_commands, u_boot_config, u_boot_log, request):
- datadir = u_boot_config.result_dir + '/'
- fstype = request.param
- imagename = datadir + "3GB." + fstype + ".img"
- mountpath = datadir + "mnt_" + fstype
- with u_boot_log.section('Create image {0}'.format(imagename)):
fsimage = FsImage(fstype, imagename, mountpath)
fsimage.mkfs(u_boot_log)
- yield fsimage
- fsimage.unmount(u_boot_log)
+@pytest.fixture(scope="module") +def populated_image(fsimage, u_boot_log):
- try:
fsimage.mount(u_boot_log)
- except Exception as e:
pytest.skip('{0}: could not mount {1}'.format(
fsimage.fstype, fsimage.imagename))
yield None
- fsimage.create_files(u_boot_log)
- fsimage.unmount(u_boot_log)
- yield fsimage
+# 'Transfer' the image to the client and make it accessible
Please see other files to see how function comments should be formatted.
+@pytest.fixture(scope="function") +def boundimage(populated_image, u_boot_console, request):
- image = populated_image
- if request.cls.scenario == "hostfs":
image.mount(u_boot_console.log)
image.rootpath = image.mountpath + "/"
yield image
image.unmount(u_boot_console.log)
- else:
output = u_boot_console.run_command_list(
["host bind 0 {0}".format(image.imagename)])
image.rootpath = "/"
yield image
output = u_boot_console.run_command_list(["host bind 0 "])
+# Dummy test to create an image file with filesystem +# Useful to isolate fixture setup from actual tests +def test_fs_prepare_image(u_boot_config, fsimage, request):
- if not fsimage:
pytest.fail("Failed to create image")
+# Dummy test to create initial filesystem contents +def test_fs_populate_image(populated_image, request):
- if not populated_image:
pytest.fail("Failed create initial image content")
+# Scenarios: +# hostfs: access image contents through the sandbox hostfs +# facility, using the filesytem implementation of +# the sandbox host, e.g. Linux kernel +# generic: test u-boots native filesystem implementations, +# using the 'generic' command names, e.g. 'load' +# TODO - +# fscommands: test u-boots native filesystem implementations, +# using the fs specific commands, e.g. 'ext4load' +@pytest.fixture(scope="class", params=["generic", "hostfs"]) +def scenario(request):
- request.cls.scenario = request.param
- return request.param
+@pytest.mark.usefixtures("u_boot_console", "scenario") +class TestFilesystems:
- ignore_cleanup_errors = True
- filesize_regex = re.compile("^filesize=([A-Fa-f0-9]+)")
- md5sum_regex = re.compile("^md5 for .* ==> ([A-Fa-f0-9]{32})")
- dirlist_regex = re.compile("\s+(\d+)\s+(\S+.file\S*)")
Should these be self. ?
- def get_filesize(self, filename):
strides = files[filename]
return int(strides[-1][1])
- def check_dirlist(self, string, filenames):
m = self.dirlist_regex.findall(string)
assert(m)
for i, e in enumerate(m):
m[i] = (int(e[0]), e[1].lower())
for f in filenames:
e = (self.get_filesize(f), f.lower())
assert(e in m)
- def check_filesize(self, string, size):
m = self.filesize_regex.match(string)
assert(m)
assert(int(m.group(1), 16) == size)
- def check_md5sum(self, string, md5):
m = self.md5sum_regex.match(string)
assert(m)
assert(len(m.group(1)) == 32)
assert(m.group(1) == md5)
- def run_listcmd(self, rootpath, dirname):
cmd = "{0}{1} {2} {3}".format(
self.fs_params.get('prefix'),
self.fs_commands.get('listcmd'),
self.fs_params.get('interface'),
rootpath + dirname)
with self.console.log.section('List "{0}"'.format(dirname)):
output = self.console.run_command_list([cmd])
return output[0]
- def run_readcmd(self, rootpath, filename, offset, length):
cmd = "{0}{1} {2} {3} {4} 0x{5:x} 0x{6:x}".format(
self.fs_params.get('prefix'),
self.fs_commands.get('readcmd'),
self.fs_params.get('interface'),
"0", # address
rootpath + filename,
length, offset)
with self.console.log.section('Read file "{0}"'.format(filename)):
output = self.console.run_command_list(
[cmd, "env print filesize",
"md5sum 0 $filesize", "env set filesize"])
return output[1:3]
- def run_sizecmd(self, rootpath, filename):
cmd = "{0}{1} {2} {3}".format(
self.fs_params.get('prefix'),
self.fs_commands.get('sizecmd'),
self.fs_params.get('interface'),
rootpath + filename)
with self.console.log.section('Get size of "{0}"'.format(filename)):
output = self.console.run_command_list(
[cmd, "env print filesize", "env set filesize"])
return output[1]
- @pytest.mark.parametrize("dirname", ["", "./"])
- def test_fs_ls(self, boundimage, u_boot_console, dirname):
self.console = u_boot_console
self.fs_params = cmd_parameters.get(self.scenario)
self.fs_commands = fs_commands.get(boundimage.fstype)
output = self.run_listcmd(boundimage.rootpath, dirname)
self.check_dirlist(output, files.keys())
- @pytest.mark.parametrize("filename", files.keys())
- def test_fs_filesize(self, boundimage, u_boot_console, filename):
self.console = u_boot_console
self.fs_params = cmd_parameters.get(self.scenario)
self.fs_commands = fs_commands.get(boundimage.fstype)
filesize = self.get_filesize(filename)
output = self.run_sizecmd(boundimage.rootpath, filename)
self.check_filesize(output, filesize)
- @pytest.mark.parametrize("filename", files.keys())
- def test_fs_read(self, boundimage, u_boot_console, filename):
self.console = u_boot_console
self.fs_params = cmd_parameters.get(self.scenario)
self.fs_commands = fs_commands.get(boundimage.fstype)
md5s = boundimage.md5s[filename]
for i, stride in enumerate(files[filename]):
length = int(stride[1]) - int(stride[0])
output = self.run_readcmd(
boundimage.rootpath, filename, int(stride[0]), length)
self.check_filesize(output[0], length)
self.console.log.info("md5: {0}".format(md5s[i]))
self.check_md5sum(output[1], md5s[i])
- @pytest.mark.parametrize("filename", files.keys())
- def test_fs_read_head(self, boundimage, u_boot_console, filename):
self.console = u_boot_console
self.fs_params = cmd_parameters.get(self.scenario)
self.fs_commands = fs_commands.get(boundimage.fstype)
filesize = self.get_filesize(filename)
filesize = min(filesize, 4e6)
output = self.run_readcmd(
boundimage.rootpath, filename, 0, filesize)
self.check_filesize(output[0], filesize)
-- 2.10.1
Regards, Simon