From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lukasz Majewski Date: Thu, 21 Jan 2016 12:26:22 +0100 Subject: [U-Boot] [PATCH 7/8] test/py: ums: add filesystem-based testing In-Reply-To: <1453328158-23818-7-git-send-email-swarren@wwwdotorg.org> References: <1453328158-23818-1-git-send-email-swarren@wwwdotorg.org> <1453328158-23818-7-git-send-email-swarren@wwwdotorg.org> Message-ID: <20160121122622.35c931e6@amdc2363> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Stephen, > From: Stephen Warren > > 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 > Signed-off-by: Stephen Warren > --- > 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 > -# > -# 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 Stephen, thanks for converting DFU and UMS to pytest code. -- Best regards, Lukasz Majewski Samsung R&D Institute Poland (SRPOL) | Linux Platform Group