From: Dave Chinner <dchinner@xxxxxxxxxx> factor out all the test list parsing and building code to common/test_list so that it can be used by both check and check-parallel. Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> --- check | 270 +++---------------------------------------- common/report | 2 +- common/test_list | 295 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 314 insertions(+), 253 deletions(-) create mode 100644 common/test_list diff --git a/check b/check index 607d2456e..4dc266dcf 100755 --- a/check +++ b/check @@ -15,19 +15,13 @@ notrun=() interrupt=true diff="diff -u" showme=false -have_test_arg=false -randomize=false -exact_order=false export here=`pwd` -xfile="" -subdir_xfile="" brief_test_summary=false do_report=false DUMP_OUTPUT=false iterations=1 istop=false loop_on_fail=0 -exclude_tests=() # This is a global variable used to pass test failure text to reporting gunk _err_msg="" @@ -49,8 +43,9 @@ timestamp=${TIMESTAMP:=false} rm -f $tmp.list $tmp.tmp $tmp.grep $here/$iam.out $tmp.report.* $tmp.arglist -SRC_GROUPS="generic" -export SRC_DIR="tests" +# We need to include the test list processing first as argument parsing +# requires test list parsing and setup. +. ./common/test_list usage() { @@ -124,153 +119,12 @@ examples: exit 1 } -get_sub_group_list() -{ - local d=$1 - local grp=$2 - - test -s "$SRC_DIR/$d/group.list" || return 1 - - local grpl=$(sed -n < $SRC_DIR/$d/group.list \ - -e 's/#.*//' \ - -e 's/$/ /' \ - -e "s;^\($VALID_TEST_NAME\).* $grp .*;$SRC_DIR/$d/\1;p") - echo $grpl -} - -get_group_list() -{ - local grp=$1 - local grpl="" - local sub=$(dirname $grp) - local fsgroup="$FSTYP" - - if [ -n "$sub" -a "$sub" != "." -a -d "$SRC_DIR/$sub" ]; then - # group is given as <subdir>/<group> (e.g. xfs/quick) - grp=$(basename $grp) - get_sub_group_list $sub $grp - return - fi - - if [ "$FSTYP" = ext2 -o "$FSTYP" = ext3 ]; then - fsgroup=ext4 - fi - for d in $SRC_GROUPS $fsgroup; do - if ! test -d "$SRC_DIR/$d" ; then - continue - fi - grpl="$grpl $(get_sub_group_list $d $grp)" - done - echo $grpl -} - -# Find all tests, excluding files that are test metadata such as group files. -# It matches test names against $VALID_TEST_NAME defined in common/rc -get_all_tests() -{ - touch $tmp.list - for d in $SRC_GROUPS $FSTYP; do - if ! test -d "$SRC_DIR/$d" ; then - continue - fi - ls $SRC_DIR/$d/* | \ - grep -v "\..*" | \ - grep "^$SRC_DIR/$d/$VALID_TEST_NAME"| \ - grep -v "group\|Makefile" >> $tmp.list 2>/dev/null - done -} - -# takes the list of tests to run in $tmp.list, and removes the tests passed to -# the function from that list. -trim_test_list() -{ - local test_list="$*" - - rm -f $tmp.grep - local numsed=0 - for t in $test_list - do - if [ $numsed -gt 100 ]; then - grep -v -f $tmp.grep <$tmp.list >$tmp.tmp - mv $tmp.tmp $tmp.list - numsed=0 - rm -f $tmp.grep - fi - echo "^$t\$" >>$tmp.grep - numsed=`expr $numsed + 1` - done - grep -v -f $tmp.grep <$tmp.list >$tmp.tmp - mv $tmp.tmp $tmp.list - rm -f $tmp.grep -} - _timestamp() { local now=`date "+%T"` echo -n " [$now]" } -_prepare_test_list() -{ - unset list - # Tests specified on the command line - if [ -s $tmp.arglist ]; then - cat $tmp.arglist > $tmp.list - else - touch $tmp.list - fi - - # Specified groups to include - # Note that the CLI processing adds a leading space to the first group - # parameter, so we have to catch that here checking for "all" - if ! $have_test_arg && [ "$GROUP_LIST" == " all" ]; then - # no test numbers, do everything - get_all_tests - else - for group in $GROUP_LIST; do - list=$(get_group_list $group) - if [ -z "$list" ]; then - echo "Group \"$group\" is empty or not defined?" - exit 1 - fi - - for t in $list; do - grep -s "^$t\$" $tmp.list >/dev/null || \ - echo "$t" >>$tmp.list - done - done - fi - - # Specified groups to exclude - for xgroup in $XGROUP_LIST; do - list=$(get_group_list $xgroup) - if [ -z "$list" ]; then - echo "Group \"$xgroup\" is empty or not defined?" - continue - fi - - trim_test_list $list - done - - # sort the list of tests into numeric order unless we're running tests - # in the exact order specified - if ! $exact_order; then - if $randomize; then - if type shuf >& /dev/null; then - sorter="shuf" - else - sorter="awk -v seed=$RANDOM -f randomize.awk" - fi - else - sorter="cat" - fi - list=`sort -n $tmp.list | uniq | $sorter` - else - list=`cat $tmp.list` - fi - rm -f $tmp.list -} - # Process command arguments first. while [ $# -gt 0 ]; do case "$1" in @@ -285,48 +139,20 @@ while [ $# -gt 0 ]; do export OVERLAY=true ;; - -g) group=$2 ; shift ; - GROUP_LIST="$GROUP_LIST ${group//,/ }" - ;; + -g) _tl_setup_group $2 ; shift ;; + -e) _tl_setup_exclude_tests $2 ; shift ;; + -E) _tl_setup_exclude_file $2 ; shift ;; + -x) _tl_setup_exclude_group $2; shift ;; + -X) _tl_setup_exclude_subdir $2; shift ;; + -r) _tl_setup_randomise ;; + --exact-order) _tl_setup_ordered ;; - -x) xgroup=$2 ; shift ; - XGROUP_LIST="$XGROUP_LIST ${xgroup//,/ }" - ;; - - -X) subdir_xfile=$2; shift ; - ;; - -e) - xfile=$2; shift ; - readarray -t -O "${#exclude_tests[@]}" exclude_tests < \ - <(echo "$xfile" | tr ', ' '\n\n') - ;; - - -E) xfile=$2; shift ; - if [ -f $xfile ]; then - readarray -t -O ${#exclude_tests[@]} exclude_tests < \ - <(sed "s/#.*$//" $xfile) - fi - ;; -s) RUN_SECTION="$RUN_SECTION $2"; shift ;; -S) EXCLUDE_SECTION="$EXCLUDE_SECTION $2"; shift ;; -l) diff="diff" ;; -udiff) diff="$diff -u" ;; -n) showme=true ;; - -r) - if $exact_order; then - echo "Cannot specify -r and --exact-order." - exit 1 - fi - randomize=true - ;; - --exact-order) - if $randomize; then - echo "Cannnot specify --exact-order and -r." - exit 1 - fi - exact_order=true - ;; -i) iterations=$2; shift ;; -I) iterations=$2; istop=true; shift ;; -T) timestamp=true ;; @@ -344,13 +170,13 @@ while [ $# -gt 0 ]; do -*) usage ;; *) # not an argument, we've got tests now. - have_test_arg=true ;; + _tl_setup_cli $* esac # if we've found a test specification, the break out of the processing # loop before we shift the arguments so that this is the first argument # that we process in the test arg loop below. - if $have_test_arg; then + if $_tl_have_test_args; then break; fi @@ -388,51 +214,6 @@ if [ -n "$FUZZ_REWRITE_DURATION" ]; then fi fi -if [ -n "$subdir_xfile" ]; then - for d in $SRC_GROUPS $FSTYP; do - [ -f $SRC_DIR/$d/$subdir_xfile ] || continue - for f in `sed "s/#.*$//" $SRC_DIR/$d/$subdir_xfile`; do - exclude_tests+=($d/$f) - done - done -fi - -# Process tests from command line now. -if $have_test_arg; then - while [ $# -gt 0 ]; do - case "$1" in - -*) echo "Arguments before tests, please!" - status=1 - exit $status - ;; - *) # Expand test pattern (e.g. xfs/???, *fs/001) - list=$(cd $SRC_DIR; echo $1) - for t in $list; do - t=${t#$SRC_DIR/} - test_dir=${t%%/*} - test_name=${t##*/} - group_file=$SRC_DIR/$test_dir/group.list - - if grep -Eq "^$test_name" $group_file; then - # in group file ... OK - echo $SRC_DIR/$test_dir/$test_name \ - >>$tmp.arglist - else - # oops - echo "$t - unknown test, ignored" - fi - done - ;; - esac - - shift - done -elif [ -z "$GROUP_LIST" ]; then - # default group list is the auto group. If any other group or test is - # specified, we use that instead. - GROUP_LIST="auto" -fi - if [ `id -u` -ne 0 ] then echo "check: QA must be run as root" @@ -593,21 +374,6 @@ _check_filesystems() return $ret } -_expunge_test() -{ - local TEST_ID="$1" - - for f in "${exclude_tests[@]}"; do - # $f may contain traling spaces and comments - local id_regex="^${TEST_ID}\b" - if [[ "$f" =~ ${id_regex} ]]; then - echo " [expunged]" - return 0 - fi - done - return 1 -} - # retain files which would be overwritten in subsequent reruns of the same test _stash_fail_loop_files() { local seq_prefix="${REPORT_DIR}/${1}" @@ -714,7 +480,7 @@ _run_seq() { } _detect_kmemleak -_prepare_test_list +_tl_prepare_test_list fstests_start_time="$(date +"%F %T")" if $OPTIONS_HAVE_SECTIONS; then @@ -794,7 +560,7 @@ function run_section() # TEST_DEV could be changed, source common/rc again with # correct FSTYP to get FSTYP specific configs, e.g. common/xfs . common/rc - _prepare_test_list + _tl_prepare_test_list elif [ "$OLD_TEST_FS_MOUNT_OPTS" != "$TEST_FS_MOUNT_OPTS" ]; then _test_unmount 2> /dev/null if ! _test_mount @@ -859,7 +625,7 @@ function run_section() loop_status=() # track rerun-on-failure state local tc_status ix - local -a _list=( $list ) + local -a _list=( $_tl_tests ) for ((ix = 0; ix < ${#_list[*]}; !${#loop_status[*]} && ix++)); do seq="${_list[$ix]}" @@ -880,7 +646,7 @@ function run_section() # the filename for the test and the name output are different. # we don't include the tests/ directory in the name output. - export seqnum=${seq#$SRC_DIR/} + export seqnum=$(_tl_strip_src_dir $seq) group=${seqnum%%/*} if $OPTIONS_HAVE_SECTIONS; then REPORT_DIR="$RESULT_BASE/$section" @@ -902,7 +668,7 @@ function run_section() echo -n "$seqnum" if $showme; then - if _expunge_test $seqnum; then + if _tl_expunge_test $seqnum; then tc_status="expunge" else echo @@ -928,7 +694,7 @@ function run_section() rm -f $seqres.out.bad $seqres.hints # check if we really should run it - if _expunge_test $seqnum; then + if _tl_expunge_test $seqnum; then tc_status="expunge" _stash_test_status "$seqnum" "$tc_status" continue diff --git a/common/report b/common/report index 7128bbeba..5697d2540 100644 --- a/common/report +++ b/common/report @@ -196,7 +196,7 @@ _xunit_make_testcase_report() echo -e "\t\t<skipped/>" >> $report ;; "fail") - local out_src="${SRC_DIR}/${test_name}.out" + local out_src="${_tl_src_dir}/${test_name}.out" local full_file="${REPORT_DIR}/${test_name}.full" local dmesg_file="${REPORT_DIR}/${test_name}.dmesg" local outbad_file="${REPORT_DIR}/${test_name}.out.bad" diff --git a/common/test_list b/common/test_list new file mode 100644 index 000000000..2432be6f7 --- /dev/null +++ b/common/test_list @@ -0,0 +1,295 @@ +##/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (c) 2024 Red Hat, Inc. All Rights Reserved. +# +# Test list parsing and building functions +# +# Note: this file must stand alone and not be dependent on any other includes, +# most especially common/rc and common/config. This is because we have to +# include this file before option parsing, whilst the rc/config includes need to +# be included -after- option parsing. +# +# Any function or variable that is public should have a "_tl_" prefix. + +export _tl_src_dir="tests" + +_SRC_GROUPS="generic" +_GROUP_LIST= +_XGROUP_LIST= +_tl_exact_order=false +_tl_randomise=false +_tl_have_test_args=false +_tl_file="$tmp.test_list" +_tl_exclude_tests=() +_tl_tests= + +_tl_strip_src_dir() +{ + local test="$1" + + echo ${test#$_tl_src_dir/} +} + +get_sub_group_list() +{ + local d=$1 + local grp=$2 + + test -s "$_tl_src_dir/$d/group.list" || return 1 + + local grpl=$(sed -n < $_tl_src_dir/$d/group.list \ + -e 's/#.*//' \ + -e 's/$/ /' \ + -e "s;^\($VALID_TEST_NAME\).* $grp .*;$_tl_src_dir/$d/\1;p") + echo $grpl +} + +get_group_list() +{ + local grp=$1 + local grpl="" + local sub=$(dirname $grp) + local fsgroup="$FSTYP" + + if [ -n "$sub" -a "$sub" != "." -a -d "$_tl_src_dir/$sub" ]; then + # group is given as <subdir>/<group> (e.g. xfs/quick) + grp=$(basename $grp) + get_sub_group_list $sub $grp + return + fi + + if [ "$FSTYP" = ext2 -o "$FSTYP" = ext3 ]; then + fsgroup=ext4 + fi + for d in $_SRC_GROUPS $fsgroup; do + if ! test -d "$_tl_src_dir/$d" ; then + continue + fi + grpl="$grpl $(get_sub_group_list $d $grp)" + done + echo $grpl +} + +# Find all tests, excluding files that are test metadata such as group files. +# It matches test names against $VALID_TEST_NAME defined in common/rc +get_all_tests() +{ + touch $tmp.list + for d in $_SRC_GROUPS $FSTYP; do + if ! test -d "$_tl_src_dir/$d" ; then + continue + fi + ls $_tl_src_dir/$d/* | \ + grep -v "\..*" | \ + grep "^$_tl_src_dir/$d/$VALID_TEST_NAME"| \ + grep -v "group\|Makefile" >> $tmp.list 2>/dev/null + done +} + +# takes the list of tests to run in $tmp.list, and removes the tests passed to +# the function from that list. +trim_test_list() +{ + local test_list="$*" + + rm -f $tmp.grep + local numsed=0 + for t in $test_list + do + if [ $numsed -gt 100 ]; then + grep -v -f $tmp.grep <$tmp.list >$tmp.tmp + mv $tmp.tmp $tmp.list + numsed=0 + rm -f $tmp.grep + fi + echo "^$t\$" >>$tmp.grep + numsed=`expr $numsed + 1` + done + grep -v -f $tmp.grep <$tmp.list >$tmp.tmp + mv $tmp.tmp $tmp.list + rm -f $tmp.grep +} + +_tl_prepare_test_list() +{ + unset _tl_tests + # Tests specified on the command line + if [ -s $_tl_file ]; then + cat $_tl_file > $tmp.list + else + touch $tmp.list + fi + + # Specified groups to include + # Note that the CLI processing adds a leading space to the first group + # parameter, so we have to catch that here checking for "all" + if ! $_tl_have_test_args && [ "$_GROUP_LIST" == " all" ]; then + # no test numbers, do everything + get_all_tests + else + for group in $_GROUP_LIST; do + list=$(get_group_list $group) + if [ -z "$list" ]; then + echo "Group \"$group\" is empty or not defined?" + exit 1 + fi + + for t in $list; do + grep -s "^$t\$" $tmp.list >/dev/null || \ + echo "$t" >>$tmp.list + done + done + fi + + # Specified groups to exclude + for xgroup in $_XGROUP_LIST; do + list=$(get_group_list $xgroup) + if [ -z "$list" ]; then + echo "Group \"$xgroup\" is empty or not defined?" + continue + fi + + trim_test_list $list + done + + # sort the list of tests into numeric order unless we're running tests + # in the exact order specified + if ! $_tl_exact_order; then + if $_tl_randomise; then + if type shuf >& /dev/null; then + sorter="shuf" + else + sorter="awk -v seed=$RANDOM -f randomize.awk" + fi + else + sorter="cat" + fi + _tl_tests=`sort -n $tmp.list | uniq | $sorter` + else + _tl_tests=`cat $tmp.list` + fi + rm -f $tmp.list +} + +_tl_expunge_test() +{ + local TEST_ID="$1" + + for f in "${_tl_exclude_tests[@]}"; do + # $f may contain traling spaces and comments + local id_regex="^${TEST_ID}\b" + if [[ "$f" =~ ${id_regex} ]]; then + echo " [expunged]" + return 0 + fi + done + return 1 +} + +_tl_setup_exclude_tests() +{ + local list="$1" + + readarray -t -O "${#_tl_exclude_tests[@]}" _tl_exclude_tests < \ + <(echo "$list" | tr ', ' '\n\n') +} + +_tl_setup_exclude_file() +{ + local xfile="$1" + + if [ -f $xfile ]; then + readarray -t -O ${#_tl_exclude_tests[@]} _tl_exclude_tests < \ + <(sed "s/#.*$//" $xfile) + fi +} + +_tl_setup_exclude_subdir() +{ + local xfile="$1" + local d + local f + + [ -z "$xfile" ] && return + + for d in $_SRC_GROUPS $FSTYP; do + [ -f $_tl_src_dir/$d/$xfile ] || continue + for f in `sed "s/#.*$//" $_tl_src_dir/$d/$xfile`; do + _tl_exclude_tests+=($d/$f) + done + done +} + +_tl_setup_exclude_group() +{ + local xgroup="$1" + + _XGROUP_LIST="$_XGROUP_LIST ${xgroup//,/ }" +} + +_tl_setup_group() +{ + local group="$1" + + _GROUP_LIST="$_GROUP_LIST ${group//,/ }" +} + +_tl_setup_randomise() +{ + if $_tl_exact_order; then + echo "Cannot specify -r and --exact-order." + exit 1 + fi + _tl_randomise=true +} + +_tl_setup_ordered() +{ + if $_tl_randomise; then + echo "Cannnot specify --exact-order and -r." + exit 1 + fi + _tl_exact_order=true +} + +_tl_setup_cli() +{ + while [ $# -gt 0 ]; do + case "$1" in + -*) echo "Arguments before tests, please!" + status=1 + exit $status + ;; + *) # Expand test pattern (e.g. xfs/???, *fs/001) + local list=$(cd $_tl_src_dir; echo $1) + local t + + for t in $list; do + t=${t#$_tl_src_dir/} + local test_dir=${t%%/*} + local test_name=${t##*/} + local group_file=$_tl_src_dir/$test_dir/group.list + + if grep -Eq "^$test_name" $group_file; then + # in group file ... OK + echo $_tl_src_dir/$test_dir/$test_name \ + >> $_tl_file + _tl_have_test_args=true + else + # oops + echo "$t - unknown test, ignored" + fi + done + ;; + esac + + shift + done + + if ! $_tl_have_test_args && [ -z "$_GROUP_LIST" ]; then + # default group list is the auto group. If any other group or + # test is specified, we use that instead. + _GROUP_LIST="auto" + fi +} -- 2.45.2