Ticket #3730: 3730-0002-extfs-introduce-a-tester.patch

File 3730-0002-extfs-introduce-a-tester.patch, 15.6 KB (added by mooffie, 7 years ago)
  • tests/src/extfs-helpers-listcmd/Makefile.am

    From 784abf62f701f5d745a89de6ec40f993c6352f6d Mon Sep 17 00:00:00 2001
    From: Mooffie <mooffie@gmail.com>
    Date: Fri, 18 Nov 2016 15:38:52 +0200
    Subject: [PATCH 02/11] extfs: introduce a tester.
    
    This tester tests that helpers implement the "list" command correctly.
    ---
     tests/src/extfs-helpers-listcmd/Makefile.am |  30 ++-
     tests/src/extfs-helpers-listcmd/data/dummy  |   3 +
     tests/src/extfs-helpers-listcmd/mc_xcat     |  16 ++
     tests/src/extfs-helpers-listcmd/run         |  15 --
     tests/src/extfs-helpers-listcmd/test_all    | 393 ++++++++++++++++++++++++++++
     5 files changed, 441 insertions(+), 16 deletions(-)
     create mode 100644 tests/src/extfs-helpers-listcmd/data/dummy
     create mode 100755 tests/src/extfs-helpers-listcmd/mc_xcat
     delete mode 100755 tests/src/extfs-helpers-listcmd/run
     create mode 100755 tests/src/extfs-helpers-listcmd/test_all
    
    diff --git a/tests/src/extfs-helpers-listcmd/Makefile.am b/tests/src/extfs-helpers-listcmd/Makefile.am
    index 043fa8a..bd4dbe1 100644
    a b LIBS = $(top_builddir)/lib/libmc.la 
    1010 
    1111# Programs/scripts to build on 'make check'. 
    1212check_PROGRAMS = mc_parse_ls_l 
     13check_SCRIPTS = run 
    1314 
    1415# Tests to run on 'make check' 
    1516TESTS = run 
    1617 
     18# On 'make clean', delete 'run' as well. 
     19CLEANFILES = run 
     20 
    1721mc_parse_ls_l_SOURCES = \ 
    1822        mc_parse_ls_l.c 
    1923 
    20 EXTRA_DIST = run 
     24data_files_to_distribute = \ 
     25        data/dummy 
     26 
     27EXTRA_DIST = mc_xcat test_all $(data_files_to_distribute) 
     28 
     29run: 
     30        echo '#!/bin/sh' > $@ 
     31        echo >> $@ 
     32        echo '# This script is an easy way to launch the "test_all" script' >> $@ 
     33        echo '# with all the required arguments.' >> $@ 
     34        echo '#' >> $@ 
     35        echo '# Run this script with "--help" to learn more.' >> $@ 
     36        echo >> $@ 
     37        echo '# Where to find mc_parse_ls_l and mc_xcat, respectively.' >> $@ 
     38        echo 'PATH="$(abs_builddir):$(abs_srcdir):$$PATH"' >> $@ 
     39        echo >> $@ 
     40# The 'abs_' isn't mandatory. It lets you move this script out of the build tree. 
     41        echo '"$(abs_srcdir)"/test_all "$$@" \' >> $@ 
     42        echo '  --data-dir "$(abs_srcdir)/data" \' >> $@ 
     43# Before installation, some helpers are in the build tree, some in the src tree. 
     44        echo '  --helpers-dir "$(abs_top_builddir)/src/vfs/extfs/helpers" \' >> $@ 
     45        echo '  --helpers-dir "$(abs_top_srcdir)/src/vfs/extfs/helpers"' >> $@ 
     46        chmod +x $@ 
     47# (We can alternatively create run from a run.in template 
     48# with 'AC_CONFIG_FILES[run, chmod +x run]'.) 
  • new file tests/src/extfs-helpers-listcmd/data/dummy

    diff --git a/tests/src/extfs-helpers-listcmd/data/dummy b/tests/src/extfs-helpers-listcmd/data/dummy
    new file mode 100644
    index 0000000..e9c581d
    - +  
     1This is a dummy file meant to ensure this directory isn't empty so that git always creates it. 
     2 
     3Otherwise our 'test_all' script will fail complaining the directory doesn't exist. 
  • new file tests/src/extfs-helpers-listcmd/mc_xcat

    diff --git a/tests/src/extfs-helpers-listcmd/mc_xcat b/tests/src/extfs-helpers-listcmd/mc_xcat
    new file mode 100755
    index 0000000..7871a8f
    - +  
     1#!/bin/sh 
     2 
     3# 
     4# This program is intended to be identical to 'cat' with the exception that 
     5# it ignores any arguments past the 1st one. 
     6# 
     7# To understand why it's needed, first read the section about 
     8# MC_TEST_EXTFS_LIST_CMD in the README. As explained there, the command in 
     9# MC_TEST_EXTFS_LIST_CMD has to ignore any extra arguments passed to it. 
     10# The tester achieves this by invoking a helper thus (roughly): 
     11# 
     12#    export MC_TEST_EXTFS_LIST_CMD="mc_xcat /path/to/fake/input" 
     13#    sh /path/to/helper list /dev/null 
     14# 
     15 
     16exec cat "$1" 
  • deleted file tests/src/extfs-helpers-listcmd/run

    diff --git a/tests/src/extfs-helpers-listcmd/run b/tests/src/extfs-helpers-listcmd/run
    deleted file mode 100755
    index 7f905e0..0000000
    + -  
    1 #!/bin/sh 
    2  
    3 echo 
    4 echo "This is a placeholder." 
    5 echo "It will be replaced in the future with a script that does the real" 
    6 echo "work of testing the helpers." 
    7 echo 
    8 echo "Here's a silly test to check whether 'ls', had it been an extfs helper," 
    9 echo "works properly:" 
    10 echo 
    11  
    12 LC_ALL=C ls -l | ./mc_parse_ls_l 
    13  
    14 # (LC_ALL=C is meant to prevent date formats MC can't parse. This might 
    15 # still not be foolproof, but that's just a demonstration.) 
  • new file tests/src/extfs-helpers-listcmd/test_all

    diff --git a/tests/src/extfs-helpers-listcmd/test_all b/tests/src/extfs-helpers-listcmd/test_all
    new file mode 100755
    index 0000000..89d5c77
    - +  
     1#!/bin/sh 
     2 
     3# A tester for extfs helpers. 
     4# 
     5# Copyright (C) 2016 
     6# The Free Software Foundation, Inc. 
     7# 
     8# This file is part of the Midnight Commander. 
     9# 
     10# The Midnight Commander is free software: you can redistribute it 
     11# and/or modify it under the terms of the GNU General Public License as 
     12# published by the Free Software Foundation, either version 3 of the License, 
     13# or (at your option) any later version. 
     14# 
     15# The Midnight Commander is distributed in the hope that it will be useful, 
     16# but WITHOUT ANY WARRANTY; without even the implied warranty of 
     17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     18# GNU General Public License for more details. 
     19# 
     20# You should have received a copy of the GNU General Public License 
     21# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     22 
     23help() { 
     24  cat << EOS 
     25 
     26NAME 
     27 
     28$(basename "$0") - Tests the 'list' command of extfs helpers. 
     29 
     30SYNOPSIS 
     31 
     32  $(basename "$0") \\ 
     33     --data-dir /path/to/where/data/files/are/stored \\ 
     34     --helpers-dir /path/to/where/helpers/are/stored 
     35 
     36(But you're more likely to invoke this program with the 'run' script 
     37created by 'make check'; or by 'make check' itself.) 
     38 
     39DESCRIPTION 
     40 
     41This program tests extfs helpers by feeding them input and comparing 
     42their output to the expected output. 
     43 
     44See README for full details. 
     45 
     46You need to tell this program two things: where the helpers are stored, 
     47and where the "data files" are stored. The data files are *.input files 
     48that are fed to the helpers and *.output files that are the correct 
     49output expected from these helpers. 
     50 
     51EOS 
     52} 
     53 
     54#"' 
     55 
     56############################ Global variables ############################## 
     57 
     58# The directories used. 
     59DATA_DIR= 
     60HELPERS_DIR1= 
     61HELPERS_DIR2= 
     62 
     63opt_create_output=no        # "yes" if '--create-output' provided. 
     64opt_run_mcdiff_on_error=no  # "yes" if '--mcdiff' provided. 
     65 
     66############################ Coding guidance ############################### 
     67 
     68# 
     69# Portability notes: 
     70# 
     71# - We do `local var="$whatever"` instead of `local var=$whatever` for 
     72#   compatibility with Dash. See http://unix.stackexchange.com/questions/97560. 
     73# 
     74# - The 'local' keyword used in this file isn't mandatory. Feel free to 
     75#   remove it if it isn't supported by your archaic shell. 
     76# 
     77 
     78############################ Utility functions ############################# 
     79 
     80# 
     81# Does $1 contain $2? 
     82# 
     83# Accepts basic regex. 
     84# 
     85has_string() { 
     86  local haystack="$1"  # quotes needed for Dash, as may contain spaces (see notes above). 
     87  local needle="$2" 
     88  echo "$haystack" | grep "$needle" > /dev/null 
     89} 
     90 
     91# 
     92# Given "/path/to/basename.and.some.ext", returns "basename" 
     93# 
     94basename_sans_extensions() { 
     95  local base="$(basename "$1")" 
     96  echo "${base%%.*}" 
     97} 
     98 
     99# 
     100# Does an executable exist? 
     101# 
     102has_prog() { 
     103  # see http://stackoverflow.com/questions/592620 
     104  command -v "$1" >/dev/null 2>&1 
     105} 
     106 
     107# 
     108# Can we use colors? 
     109# 
     110has_colors() { 
     111  [ -t 1 ] && has_string "$TERM" 'linux\|xterm\|screen\|tmux\|putty' 
     112} 
     113 
     114init_colors() { 
     115  if has_colors; then 
     116    ESC=$(printf '\033')  # for portability 
     117    C_bold="$ESC[1m" 
     118    C_green="$ESC[1;32m" 
     119    C_red="$ESC[1;31m" 
     120    C_magenta="$ESC[1;35m" 
     121    C_norm="$ESC[0m" 
     122  fi 
     123} 
     124 
     125# 
     126# A few colorful alternatives to 'echo'. 
     127# 
     128header()  { echo $C_bold"$@"$C_norm; } 
     129err()     { echo $C_red"$@"$C_norm; } 
     130notice()  { echo $C_magenta"$@"$C_norm; } 
     131success() { echo $C_green"$@"$C_norm; } 
     132 
     133die() { 
     134  err "Error: $@" 
     135  exit 1 
     136} 
     137 
     138assert_dir_exists() { 
     139  [ -d "$1" ] || die "The directory '$1' doesn't exist, or is not a directory." 
     140} 
     141 
     142# 
     143# Creates a temporary file. 
     144# 
     145temp_file() { 
     146  local template="$1" 
     147  # BSD's doesn't support -t. 
     148  mktemp "${TMPDIR:-/tmp}/$template" 
     149} 
     150 
     151################################ Main code ################################# 
     152 
     153# 
     154# Prints out the command to run a helper, if it can find it. 
     155# 
     156# For example, 
     157# 
     158#    find_helper uzip /path/to/helpers/dir 
     159# 
     160# prints: 
     161# 
     162#    /usr/bin/perl -w /path/to/helpers/dir/uzip 
     163# 
     164# Since helpers in the build tree don't yet have executable bit set, we 
     165# need to extract the shebang line. 
     166# 
     167find_helper() { 
     168  local helper_name="$1" 
     169  local dir="$2" 
     170 
     171  local try="$dir/$helper_name" 
     172  if [ -f "$try" ]; then 
     173    helper_CMD="$(head -1 $try | cut -c 3-) $try"  # reason #1 we don't allow spaces in pathnames. 
     174    true 
     175  else 
     176    false 
     177  fi 
     178} 
     179 
     180# 
     181# The crux of this program. 
     182# 
     183run() { 
     184 
     185  local error_count=0 
     186  local pass_count=0 
     187 
     188  for INPUT in "$DATA_DIR"/*.input; do 
     189 
     190    has_string "$INPUT" '\*' && break  # we can't use 'shopt -s nullglob' as it's bash-specific. 
     191 
     192    header "Testing $INPUT" 
     193 
     194    has_string "$INPUT" " " && die "Error: filename contains spaces." 
     195 
     196    # 
     197    # Set up variables: 
     198    # 
     199 
     200    local helper_name="$(basename_sans_extensions "$INPUT")" 
     201    local expected_parsed_output="${INPUT%.input}.output" 
     202    local env_vars_file="${INPUT%.input}.env_vars" 
     203    local args_file="${INPUT%.input}.args" 
     204 
     205    local do_create_output=no 
     206 
     207    if [ ! -f "$expected_parsed_output" ]; then 
     208      # Corresponding *.output file doesn't exist. We either create it, later, or exit with error. 
     209      if [ $opt_create_output = "yes" ]; then 
     210        do_create_output=yes 
     211      else 
     212        err 
     213        err "Missing file: '$expected_parsed_output'." 
     214        err "You have to create an '.output' file for each '.input' one." 
     215        err 
     216        notice "Tip: invoke this program with '--create-output' to" 
     217        notice "automatically create missing '.output' files." 
     218        notice 
     219        exit 1 
     220      fi 
     221    fi 
     222 
     223    find_helper "$helper_name" "$HELPERS_DIR1" || 
     224      find_helper "$helper_name" "$HELPERS_DIR2" || 
     225        die "I can't find helper '$helper_name' in either $HELPERS_DIR1 or $HELPERS_DIR2" 
     226 
     227    local extra_parser_args="" 
     228    [ -f "$args_file" ] && extra_parser_args="$(cat "$args_file")" 
     229 
     230    local actual_output="$(temp_file $helper_name.actual-output.XXXXXXXX)" 
     231    local actual_parsed_output="$(temp_file $helper_name.actual-parsed-output.XXXXXXXX)" 
     232 
     233    # 
     234    # Variables are all set. Now do the actual stuff: 
     235    # 
     236 
     237    ( 
     238    MC_TEST_EXTFS_LIST_CMD="mc_xcat $INPUT"  # reason #2 we don't allow spaces in pathnames. 
     239    export MC_TEST_EXTFS_LIST_CMD 
     240    if [ -f "$env_vars_file" ]; then 
     241      set -a  # "allexport: Export all variables assigned to." 
     242      . "$env_vars_file" 
     243      set +a 
     244    fi 
     245    $helper_CMD list /dev/null > "$actual_output" 
     246    ) 
     247 
     248    error_count=$((error_count + 1))  # we'll decrement it later. 
     249 
     250    if [ ! -s "$actual_output" ]; then 
     251       err 
     252       err "The helper '$helper_name' produced no output for this input. Something is wrong." 
     253       err 
     254       err "Make sure this helper supports testability: that it uses \$MC_TEST_EXTFS_LIST_CMD." 
     255       err 
     256       err "You may try running the helper yourself with:" 
     257       err 
     258       err "  \$ MC_TEST_EXTFS_LIST_CMD=\"mc_xcat $INPUT\" \\" 
     259       err "      $helper_CMD list /dev/null" 
     260       err 
     261       continue 
     262    fi 
     263 
     264    # '--symbolic-ids': uid/gid aren't portable between computers, 
     265    # of course, so we always represent them symbolically when possible. 
     266    if ! mc_parse_ls_l --symbolic-ids $extra_parser_args "$actual_output" > "$actual_parsed_output"; then 
     267       err 
     268       err "ERROR: Parsing of the output of the helper '$helper_name' has failed." 
     269       err "This means that $helper_name has produced output that MC won't be able to parse." 
     270       err "Run the parsing command yourself ('mc_parse_ls_l $extra_parser_args $actual_output')" 
     271       err "to figure out the problem." 
     272       err 
     273       continue 
     274    fi 
     275 
     276    if [ $do_create_output = "yes" ]; then 
     277      # We arrive here if we were invoked with '--create-output' and 
     278      # the .output file doesn't exist. We create it and move to the next iteration. 
     279      cp "$actual_parsed_output" "$expected_parsed_output" 
     280      notice "The output file has been created in $expected_parsed_output" 
     281      continue 
     282    fi 
     283 
     284    if ! cmp "$expected_parsed_output" "$actual_parsed_output"; then 
     285       err 
     286       err "ERROR: $helper_name has produced output that's different than the expected output." 
     287       err 
     288       err "  Expected output (after parsing): $expected_parsed_output" 
     289       err "  Actual output (after parsing): $actual_parsed_output" 
     290       err 
     291       err "This might mean that a bug was introduced into $helper_name. Or that a bug was fixed." 
     292       err "Please compare the files." 
     293       err 
     294       err "If the actual output is the correct one, just copy the latter file" 
     295       err "onto the former (and commit to the git repository)." 
     296       err 
     297       if [ $opt_run_mcdiff_on_error = "yes" ]; then 
     298         notice "Hit ENTER to launch mcdiff ..." 
     299         read DUMMY_VAR  # dash needs this. 
     300         ${MCDIFF:-mcdiff} "$expected_parsed_output" "$actual_parsed_output" 
     301       else 
     302         notice "Tip: invoke this program with '--mcdiff' to automatically launch" 
     303         notice "mcdiff to visually inspect the diff." 
     304         notice 
     305       fi 
     306       continue 
     307    fi 
     308 
     309    rm "$actual_output" "$actual_parsed_output" 
     310 
     311    error_count=$((error_count - 1))  # cancel the earlier "+1". 
     312    pass_count=$((pass_count + 1)) 
     313 
     314    success "PASSED." 
     315 
     316  done 
     317 
     318  [ $pass_count = "0" -a $error_count = "0" ] && notice "Note: The data directory contains no *.input files." 
     319 
     320  [ $error_count = "0" ]  # exit status of function. 
     321} 
     322 
     323parse_command_line_arguments() { 
     324  # We want --long-options, so we don't use 'getopts'. 
     325  while [ -n "$1" ]; do 
     326    case "$1" in 
     327      --data-dir) 
     328        DATA_DIR=$2 
     329        shift 2 
     330        ;; 
     331      --helpers-dir) 
     332        if [ -z "$HELPERS_DIR1" ]; then 
     333          HELPERS_DIR1=$2 
     334        else 
     335          HELPERS_DIR2=$2 
     336        fi 
     337        shift 2 
     338        ;; 
     339      --create-output) 
     340        opt_create_output=yes 
     341        shift 
     342        ;; 
     343      --mcdiff) 
     344        opt_run_mcdiff_on_error=yes 
     345        shift 
     346        ;; 
     347      --help|-h) 
     348        help 
     349        exit 
     350        ;; 
     351      *) 
     352        die "Unknown command-line option $1" 
     353        ;; 
     354    esac 
     355  done 
     356} 
     357 
     358# 
     359# Check that everything is set up correctly. 
     360# 
     361verify_setup() { 
     362  [ -n "$DATA_DIR" ] || die "You didn't specify the data dir (--data-dir). Run me with --help for info." 
     363  [ -n "$HELPERS_DIR1" ] || die "You didn't specify the helpers dir (--helpers-dir). Run me with --help for info." 
     364  [ -z "$HELPERS_DIR2" ] && HELPERS_DIR2=$HELPERS_DIR1  # we're being lazy. 
     365 
     366  local dir 
     367  for dir in "$DATA_DIR" "$HELPERS_DIR1" "$HELPERS_DIR2"; do 
     368    assert_dir_exists "$dir" 
     369    has_string "$dir" " " && die "$dir: Sorry, spaces aren't allowed in pathnames."  # search "reason", twice, above. 
     370  done 
     371 
     372  local missing_progs="" 
     373  check_prog() { 
     374    if ! has_prog "$1"; then 
     375      err "I can't see the program '$1'." 
     376      missing_progs="${missing_progs}${missing_progs:+ and }'$1'" 
     377    fi 
     378  } 
     379 
     380  check_prog "mc_parse_ls_l" 
     381  check_prog "mc_xcat" 
     382  check_prog "mktemp"  # non-POSIX 
     383  [ -z "$missing_progs" ] || die "You need to add to your PATH the directories containing the executables $missing_progs." 
     384} 
     385 
     386main() { 
     387  init_colors 
     388  parse_command_line_arguments "$@" 
     389  verify_setup 
     390  run  # being the last command executed, its exit status is that of this whole script. 
     391} 
     392 
     393main "$@"