[U-Boot] [PATCH 7/8] test/py: ums: add filesystem-based testing
Lukasz Majewski
l.majewski at samsung.com
Thu Jan 21 12:26:22 CET 2016
Hi Stephen,
> From: Stephen Warren <swarren at nvidia.com>
>
> Enhance the UMS test to optionally mount a partition and read/write a
> file to it, validating that the content written and read back are
> identical.
>
> This enhancement is backwards-compatible; old boardenv contents that
> don't define the new configuration data will cause the test code to
> perform as before.
>
> test/ums/ is deleted since the Python test now performs the same
> testing that it did.
>
> The code is also re-written to make use of the recently added utility
> module, and split it up into nested functions so the overall logic of
> the test process can be followed more easily without the details
> cluttering the code.
>
> Cc: Lukasz Majewski <l.majewski at samsung.com>
> Signed-off-by: Stephen Warren <swarren at nvidia.com>
> ---
> test/py/tests/test_ums.py | 212
> +++++++++++++++++++++++++++++++++++---------
> test/ums/README | 30 ------- test/ums/ums_gadget_test.sh
> | 183 -------------------------------------- 3 files changed, 169
> insertions(+), 256 deletions(-) delete mode 100644 test/ums/README
> delete mode 100755 test/ums/ums_gadget_test.sh
>
> diff --git a/test/py/tests/test_ums.py b/test/py/tests/test_ums.py
> index a137221c7a5b..cb6e5ef8c20b 100644
> --- a/test/py/tests/test_ums.py
> +++ b/test/py/tests/test_ums.py
> @@ -7,8 +7,11 @@
> # should be enhanced to validate disk IO.
>
> import os
> +import os.path
> import pytest
> +import re
> import time
> +import u_boot_utils
>
> '''
> Note: This test relies on:
> @@ -17,13 +20,36 @@ a) boardenv_* to contain configuration values to
> define which USB ports are available for testing. Without this, this
> test will be automatically skipped. For example:
>
> +# Leave this list empty if you have no block_devs below with writable
> +# partitions defined.
> +env__mount_points = (
> + "/mnt/ubtest-mnt-p2371-2180-na",
> +)
> +
> env__usb_dev_ports = (
> - {'tgt_usb_ctlr': '0', 'host_ums_dev_node':
> '/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0'},
> + {
> + "tgt_usb_ctlr": "0",
> + "host_ums_dev_node":
> "/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0",
> + },
> )
>
> env__block_devs = (
> - {'type': 'mmc', 'id': '0'}, # eMMC; always present
> - {'type': 'mmc', 'id': '1'}, # SD card; present since I plugged
> one in
> + # eMMC; always present
> + {
> + "type": "mmc",
> + "id": "0",
> + # The following two properties are optional.
> + # If present, the partition will be mounted and a file
> written-to and
> + # read-from it. If missing, only a simple block read test
> will be
> + # performed.
> + "writable_fs_partition": 1,
> + "writable_fs_subdir": "tmp/",
> + },
> + # SD card; present since I plugged one in
> + {
> + "type": "mmc",
> + "id": "1"
> + },
> )
>
> b) udev rules to set permissions on devices nodes, so that sudo is
> not @@ -34,41 +60,15 @@ ACTION=="add", SUBSYSTEM=="block",
> SUBSYSTEMS=="usb", KERNELS=="3-13", MODE:="66 (You may wish to change
> the group ID instead of setting the permissions wide open. All that
> matters is that the user ID running the test can access the device.)
> -'''
>
> -def open_ums_device(host_ums_dev_node):
> - '''Attempt to open a device node, returning either the opened
> file handle,
> - or None on any error.'''
> +c) /etc/fstab entries to allow the block device to be mounted
> without requiring +root permissions. For example:
>
> - try:
> - return open(host_ums_dev_node, 'rb')
> - except:
> - return None
> -
> -def wait_for_ums_device(host_ums_dev_node):
> - '''Continually attempt to open the device node exported by the
> "ums"
> - command, and either return the opened file handle, or raise an
> exception
> - after a timeout.'''
> -
> - for i in xrange(100):
> - fh = open_ums_device(host_ums_dev_node)
> - if fh:
> - return fh
> - time.sleep(0.1)
> - raise Exception('UMS device did not appear')
> -
> -def wait_for_ums_device_gone(host_ums_dev_node):
> - '''Continually attempt to open the device node exported by the
> "ums"
> - command, and either return once the device has disappeared, or
> raise an
> - exception if it does not before a timeout occurs.'''
> -
> - for i in xrange(100):
> - fh = open_ums_device(host_ums_dev_node)
> - if not fh:
> - return
> - fh.close()
> - time.sleep(0.1)
> - raise Exception('UMS device did not disappear')
> +/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0-part1 /mnt/ubtest-mnt-p2371-2180-na
> ext4 noauto,user,nosuid,nodev +
> +This entry is only needed if any block_devs above contain a
> +writable_fs_partition value.
> +'''
>
> @pytest.mark.buildconfigspec('cmd_usb_mass_storage')
> def test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
> @@ -76,6 +76,14 @@ def test_ums(u_boot_console, env__usb_dev_port,
> env__block_devs): device when "ums" is running, and this device must
> disappear when "ums" is aborted.'''
>
> + have_writable_fs_partition = 'writable_fs_partition' in
> env__block_devs[0]
> + if not have_writable_fs_partition:
> + # If 'writable_fs_subdir' is missing, we'll skip all parts
> of the
> + # testing which mount filesystems.
> + u_boot_console.log.warning(
> + 'boardenv missing "writable_fs_partition"; ' +
> + 'UMS testing will be limited.')
> +
> tgt_usb_ctlr = env__usb_dev_port['tgt_usb_ctlr']
> host_ums_dev_node = env__usb_dev_port['host_ums_dev_node']
>
> @@ -84,11 +92,129 @@ def test_ums(u_boot_console, env__usb_dev_port,
> env__block_devs): # device list here. We'll test each block device
> somewhere else. tgt_dev_type = env__block_devs[0]['type']
> tgt_dev_id = env__block_devs[0]['id']
> + if have_writable_fs_partition:
> + mount_point =
> u_boot_console.config.env['env__mount_points'][0]
> + mount_subdir = env__block_devs[0]['writable_fs_subdir']
> + part_num = env__block_devs[0]['writable_fs_partition']
> + host_ums_part_node = '%s-part%d' % (host_ums_dev_node,
> part_num)
> + else:
> + host_ums_part_node = host_ums_dev_node
> +
> + test_f = u_boot_utils.PersistentRandomFile(u_boot_console,
> 'ums.bin',
> + 1024 * 1024);
> + if have_writable_fs_partition:
> + mounted_test_fn = mount_point + '/' + mount_subdir +
> test_f.fn +
> + def start_ums():
> + '''Start U-Boot's ums shell command.
> +
> + This also waits for the host-side USB enumeration process to
> complete. +
> + Args:
> + None.
> +
> + Returns:
> + Nothing.
> + '''
> +
> + u_boot_console.log.action(
> + 'Starting long-running U-Boot ums shell command')
> + cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type,
> tgt_dev_id)
> + u_boot_console.run_command(cmd, wait_for_prompt=False)
> + u_boot_console.wait_for(re.compile('UMS: LUN.*[\r\n]'))
> + fh =
> u_boot_utils.wait_until_open_succeeds(host_ums_part_node)
> + u_boot_console.log.action('Reading raw data from UMS device')
> + fh.read(4096)
> + fh.close()
> +
> + def mount():
> + '''Mount the block device that U-Boot exports.
> +
> + Args:
> + None.
> +
> + Returns:
> + Nothing.
> + '''
>
> - cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
> - u_boot_console.run_command('ums 0 mmc 0', wait_for_prompt=False)
> - fh = wait_for_ums_device(host_ums_dev_node)
> - fh.read(4096)
> - fh.close()
> - u_boot_console.ctrlc()
> - wait_for_ums_device_gone(host_ums_dev_node)
> + u_boot_console.log.action('Mounting exported UMS device')
> + cmd = ('/bin/mount', host_ums_part_node)
> + u_boot_utils.run_and_log(u_boot_console, cmd)
> +
> + def umount(ignore_errors):
> + '''Unmount the block device that U-Boot exports.
> +
> + Args:
> + ignore_errors: Ignore any errors. This is useful if an
> error has
> + already been detected, and the code is performing
> best-effort
> + cleanup. In this case, we do not want to mask the
> original
> + error by "honoring" any new errors.
> +
> + Returns:
> + Nothing.
> + '''
> +
> + u_boot_console.log.action('Unmounting UMS device')
> + cmd = ('/bin/umount', host_ums_part_node)
> + u_boot_utils.run_and_log(u_boot_console, cmd, ignore_errors)
> +
> + def stop_ums(ignore_errors):
> + '''Stop U-Boot's ums shell command from executing.
> +
> + This also waits for the host-side USB de-enumeration process
> to
> + complete.
> +
> + Args:
> + ignore_errors: Ignore any errors. This is useful if an
> error has
> + already been detected, and the code is performing
> best-effort
> + cleanup. In this case, we do not want to mask the
> original
> + error by "honoring" any new errors.
> +
> + Returns:
> + Nothing.
> + '''
> +
> + u_boot_console.log.action(
> + 'Stopping long-running U-Boot ums shell command')
> + u_boot_console.ctrlc()
> + u_boot_utils.wait_until_file_open_fails(host_ums_part_node,
> + ignore_errors)
> +
> + ignore_cleanup_errors = True
> + try:
> + start_ums()
> + if not have_writable_fs_partition:
> + # Skip filesystem-based testing if not configured
> + return
> + try:
> + mount()
> + u_boot_console.log.action('Writing test file via UMS')
> + cmd = ('rm', '-f', mounted_test_fn)
> + u_boot_utils.run_and_log(u_boot_console, cmd)
> + if os.path.exists(mounted_test_fn):
> + raise Exception('Could not rm target UMS test file')
> + cmd = ('cp', test_f.abs_fn, mounted_test_fn)
> + u_boot_utils.run_and_log(u_boot_console, cmd)
> + ignore_cleanup_errors = False
> + finally:
> + umount(ignore_errors=ignore_cleanup_errors)
> + finally:
> + stop_ums(ignore_errors=ignore_cleanup_errors)
> +
> + ignore_cleanup_errors = True
> + try:
> + start_ums()
> + try:
> + mount()
> + u_boot_console.log.action('Reading test file back via
> UMS')
> + read_back_hash =
> u_boot_utils.md5sum_file(mounted_test_fn)
> + cmd = ('rm', '-f', mounted_test_fn)
> + u_boot_utils.run_and_log(u_boot_console, cmd)
> + ignore_cleanup_errors = False
> + finally:
> + umount(ignore_errors=ignore_cleanup_errors)
> + finally:
> + stop_ums(ignore_errors=ignore_cleanup_errors)
> +
> + written_hash = test_f.content_hash
> + assert(written_hash == read_back_hash)
> diff --git a/test/ums/README b/test/ums/README
> deleted file mode 100644
> index c80fbfefbf52..000000000000
> --- a/test/ums/README
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -UMS test script.
> -
> -ums_gadget_test.sh
> -==================
> -
> -Example usage:
> -1. On the target:
> - create UMS exportable partitions (with e.g. gpt write), or
> specify a
> - partition number (PART_NUM) as "-" to use the entire device
> - ums 0 mmc 0
> -2. On the host:
> - sudo test/ums/ums_gadget_test.sh VID PID PART_NUM [-f
> FILE_SYSTEM] [test_file]
> - e.g. sudo test/ums/ums_gadget_test.sh 0525 a4a5 6 -f
> vfat ./dat_14M.img -
> -... where:
> - VID - UMS device USB Vendor ID
> - PID - UMS device USB Product ID
> - PART_NUM - is the partition number on which UMS operates or "-"
> to use the
> - whole device
> -
> -Information about available partitions on the target one can read
> with using -the 'mmc part' or 'part list' commands.
> -
> -The partition num (PART_NUM) can be specified as '-' for using the
> whole device. -
> -The [-f FILE_SYSTEM] optional switch allows for formatting target
> partition to -FILE_SYSTEM.
> -
> -The last, optional [test_file] parameter is for specifying the exact
> test file -to use.
> diff --git a/test/ums/ums_gadget_test.sh b/test/ums/ums_gadget_test.sh
> deleted file mode 100755
> index 9da486b266ce..000000000000
> --- a/test/ums/ums_gadget_test.sh
> +++ /dev/null
> @@ -1,183 +0,0 @@
> -#! /bin/bash
> -
> -# Copyright (C) 2014 Samsung Electronics
> -# Lukasz Majewski <l.majewski at samsung.com>
> -#
> -# UMS operation test script
> -#
> -# SPDX-License-Identifier: GPL-2.0+
> -
> -clear
> -
> -COLOUR_RED="\33[31m"
> -COLOUR_GREEN="\33[32m"
> -COLOUR_ORANGE="\33[33m"
> -COLOUR_DEFAULT="\33[0m"
> -
> -DIR=./
> -SUFFIX=img
> -RCV_DIR=rcv/
> -LOG_FILE=./log/log-`date +%d-%m-%Y_%H-%M-%S`
> -
> -cd `dirname $0`
> -../dfu/dfu_gadget_test_init.sh 33M 97M
> -
> -cleanup () {
> - rm -rf $RCV_DIR $MNT_DIR
> -}
> -
> -control_c()
> -# run if user hits control-c
> -{
> - echo -en "\n*** CTRL+C ***\n"
> - umount $MNT_DIR
> - cleanup
> - exit 0
> -}
> -
> -# trap keyboard interrupt (control-c)
> -trap control_c SIGINT
> -
> -die () {
> - printf " $COLOUR_RED FAILED $COLOUR_DEFAULT \n"
> - cleanup
> - exit 1
> -}
> -
> -calculate_md5sum () {
> - MD5SUM=`md5sum $1`
> - MD5SUM=`echo $MD5SUM | cut -d ' ' -f1`
> - echo "md5sum:"$MD5SUM
> -}
> -
> -ums_test_file () {
> - printf
> "$COLOUR_GREEN=========================================================================================
> $COLOUR_DEFAULT\n"
> - printf "File:$COLOUR_GREEN %s $COLOUR_DEFAULT\n" $1
> -
> - mount /dev/$MEM_DEV $MNT_DIR
> - if [ -f $MNT_DIR/dat_* ]; then
> - rm $MNT_DIR/dat_*
> - fi
> -
> - cp ./$1 $MNT_DIR
> -
> - while true; do
> - umount $MNT_DIR > /dev/null 2>&1
> - if [ $? -eq 0 ]; then
> - break
> - fi
> - printf "$COLOUR_ORANGE\tSleeping to wait for
> umount...$COLOUR_DEFAULT\n"
> - sleep 1
> - done
> -
> - echo -n "TX: "
> - calculate_md5sum $1
> -
> - MD5_TX=$MD5SUM
> - sleep 1
> - N_FILE=$DIR$RCV_DIR${1:2}"_rcv"
> -
> - mount /dev/$MEM_DEV $MNT_DIR
> - cp $MNT_DIR/$1 $N_FILE || die $?
> - rm $MNT_DIR/$1
> - umount $MNT_DIR
> -
> - echo -n "RX: "
> - calculate_md5sum $N_FILE
> - MD5_RX=$MD5SUM
> -
> - if [ "$MD5_TX" == "$MD5_RX" ]; then
> - printf " $COLOUR_GREEN -------> OK $COLOUR_DEFAULT \n"
> - else
> - printf " $COLOUR_RED -------> FAILED $COLOUR_DEFAULT \n"
> - cleanup
> - exit 1
> - fi
> -}
> -
> -printf
> "$COLOUR_GREEN=========================================================================================
> $COLOUR_DEFAULT\n" -echo "U-boot UMS test program" -
> -if [ $EUID -ne 0 ]; then
> - echo "You must be root to do this." 1>&2
> - exit 100
> -fi
> -
> -if [ $# -lt 3 ]; then
> - echo "Wrong number of arguments"
> - echo "Example:"
> - echo "sudo ./ums_gadget_test.sh VID PID PART_NUM [-f ext4]
> [test_file]"
> - die
> -fi
> -
> -MNT_DIR="/mnt/tmp-ums-test"
> -
> -VID=$1; shift
> -PID=$1; shift
> -PART_NUM=$1; shift
> -
> -if [ "$1" == "-f" ]; then
> - shift
> - FS_TO_FORMAT=$1; shift
> -fi
> -
> -TEST_FILE=$1
> -
> -for f in `find /sys -type f -name idProduct`; do
> - d=`dirname ${f}`
> - if [ `cat ${d}/idVendor` != "${VID}" ]; then
> - continue
> - fi
> - if [ `cat ${d}/idProduct` != "${PID}" ]; then
> - continue
> - fi
> - USB_DEV=${d}
> - break
> -done
> -
> -if [ -z "${USB_DEV}" ]; then
> - echo "Connect target"
> - echo "e.g. ums 0 mmc 0"
> - exit 1
> -fi
> -
> -MEM_DEV=`find $USB_DEV -type d -name "sd[a-z]" | awk -F/ '{print
> $(NF)}' -` -
> -mkdir -p $RCV_DIR
> -if [ ! -d $MNT_DIR ]; then
> - mkdir -p $MNT_DIR
> -fi
> -
> -if [ "$PART_NUM" == "-" ]; then
> - PART_NUM=""
> -fi
> -MEM_DEV=$MEM_DEV$PART_NUM
> -
> -if [ -n "$FS_TO_FORMAT" ]; then
> - echo -n "Formatting partition /dev/$MEM_DEV to $FS_TO_FORMAT"
> - mkfs -t $FS_TO_FORMAT /dev/$MEM_DEV > /dev/null 2>&1
> - if [ $? -eq 0 ]; then
> - printf " $COLOUR_GREEN DONE $COLOUR_DEFAULT \n"
> - else
> - die
> - fi
> -fi
> -
> -printf "Mount: /dev/$MEM_DEV \n"
> -
> -if [ -n "$TEST_FILE" ]; then
> - if [ ! -e $TEST_FILE ]; then
> - echo "No file: $TEST_FILE"
> - die
> - fi
> - ums_test_file $TEST_FILE
> -else
> - for file in $DIR*.$SUFFIX
> - do
> - ums_test_file $file
> - done
> -fi
> -
> -cleanup
> -
> -exit 0
Acked-by: Lukasz Majewski <l.majewski at samsung.com>
Stephen, thanks for converting DFU and UMS to pytest code.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
More information about the U-Boot
mailing list