1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Runs a set of tests in a given subdirectory. 5. $(dirname "$(readlink -e "${BASH_SOURCE[0]}")")/ktap_helpers.sh 6export timeout_rc=124 7export logfile=/dev/stdout 8export per_test_logging= 9export per_test_log_dir=/tmp 10export RUN_IN_NETNS= 11 12# Defaults for "settings" file fields: 13# "timeout" how many seconds to let each test run before running 14# over our soft timeout limit. 15export kselftest_default_timeout=45 16 17# There isn't a shell-agnostic way to find the path of a sourced file, 18# so we must rely on BASE_DIR being set to find other tools. 19if [ -z "$BASE_DIR" ]; then 20 echo "Error: BASE_DIR must be set before sourcing." >&2 21 exit 1 22fi 23 24TR_CMD=$(command -v tr) 25 26# If Perl is unavailable, we must fall back to line-at-a-time prefixing 27# with sed instead of unbuffered output. 28tap_prefix() 29{ 30 if [ ! -x /usr/bin/perl ]; then 31 sed -e 's/^/# /' 32 else 33 "$BASE_DIR"/kselftest/prefix.pl 34 fi 35} 36 37tap_timeout() 38{ 39 # Make sure tests will time out if utility is available. 40 if [ -x /usr/bin/timeout ] ; then 41 /usr/bin/timeout --foreground "$kselftest_timeout" \ 42 /usr/bin/timeout "$kselftest_timeout" $1 43 else 44 $1 45 fi 46} 47 48run_one() 49{ 50 DIR="$1" 51 TEST="$2" 52 local rc test_num="$3" 53 54 BASENAME_TEST=$(basename $TEST) 55 56 # Reset any "settings"-file variables. 57 export kselftest_timeout="$kselftest_default_timeout" 58 59 # Safe default if tr not available 60 kselftest_cmd_args_ref="KSELFTEST_ARGS" 61 62 # Optional arguments for this command, possibly defined as an 63 # environment variable built using the test executable in all 64 # uppercase and sanitized substituting non acceptable shell 65 # variable name characters with "_" as in: 66 # 67 # KSELFTEST_<UPPERCASE_SANITIZED_TESTNAME>_ARGS="<options>" 68 # 69 # e.g. 70 # 71 # rtctest --> KSELFTEST_RTCTEST_ARGS="/dev/rtc1" 72 # 73 # cpu-on-off-test.sh --> KSELFTEST_CPU_ON_OFF_TEST_SH_ARGS="-a -p 10" 74 # 75 if [ -n "$TR_CMD" ]; then 76 BASENAME_SANITIZED=$(echo "$BASENAME_TEST" | \ 77 $TR_CMD -d "[:blank:][:cntrl:]" | \ 78 $TR_CMD -c "[:alnum:]_" "_" | \ 79 $TR_CMD [:lower:] [:upper:]) 80 kselftest_cmd_args_ref="KSELFTEST_${BASENAME_SANITIZED}_ARGS" 81 fi 82 83 # Load per-test-directory kselftest "settings" file. 84 settings="$BASE_DIR/$DIR/settings" 85 if [ -r "$settings" ] ; then 86 while read line ; do 87 # Skip comments. 88 if echo "$line" | grep -q '^#'; then 89 continue 90 fi 91 field=$(echo "$line" | cut -d= -f1) 92 value=$(echo "$line" | cut -d= -f2-) 93 eval "kselftest_$field"="$value" 94 done < "$settings" 95 fi 96 97 # Command line timeout overrides the settings file 98 if [ -n "$kselftest_override_timeout" ]; then 99 kselftest_timeout="$kselftest_override_timeout" 100 ktap_print_msg "overriding timeout to $kselftest_timeout" >> "$logfile" 101 else 102 ktap_print_msg "timeout set to $kselftest_timeout" >> "$logfile" 103 fi 104 105 TEST_HDR_MSG="selftests: $DIR: $BASENAME_TEST" 106 echo "# $TEST_HDR_MSG" 107 if [ ! -e "$TEST" ]; then 108 ktap_print_msg "Warning: file $TEST is missing!" 109 ktap_test_fail "$test_num $TEST_HDR_MSG" 110 rc=$KSFT_FAIL 111 else 112 if [ -x /usr/bin/stdbuf ]; then 113 stdbuf="/usr/bin/stdbuf --output=L " 114 fi 115 eval kselftest_cmd_args="\$${kselftest_cmd_args_ref:-}" 116 if [ -x "$TEST" ]; then 117 cmd="$stdbuf ./$BASENAME_TEST $kselftest_cmd_args" 118 elif [ -x "./ksft_runner.sh" ]; then 119 cmd="$stdbuf ./ksft_runner.sh ./$BASENAME_TEST" 120 else 121 ktap_print_msg "Warning: file $TEST is not executable" 122 123 if [ $(head -n 1 "$TEST" | cut -c -2) = "#!" ] 124 then 125 interpreter=$(head -n 1 "$TEST" | cut -c 3-) 126 cmd="$stdbuf $interpreter ./$BASENAME_TEST" 127 else 128 ktap_test_fail "$test_num $TEST_HDR_MSG" 129 return $KSFT_FAIL 130 fi 131 fi 132 cd `dirname $TEST` > /dev/null 133 (((( tap_timeout "$cmd" 2>&1; echo $? >&3) | 134 tap_prefix >&4) 3>&1) | 135 (read xs; exit $xs)) 4>>"$logfile" 136 rc=$? 137 case "$rc" in 138 "$KSFT_PASS") 139 ktap_test_pass "$test_num $TEST_HDR_MSG";; 140 "$KSFT_SKIP") 141 ktap_test_skip "$test_num $TEST_HDR_MSG";; 142 "$KSFT_XFAIL") 143 ktap_test_xfail "$test_num $TEST_HDR_MSG";; 144 "$timeout_rc") 145 ktap_test_fail "$test_num $TEST_HDR_MSG # TIMEOUT $kselftest_timeout seconds";; 146 *) 147 ktap_test_fail "$test_num $TEST_HDR_MSG # exit=$rc";; 148 esac 149 cd - >/dev/null 150 fi 151 152 return $rc 153} 154 155in_netns() 156{ 157 local name=$1 158 ip netns exec $name bash <<-EOF 159 BASE_DIR=$BASE_DIR 160 source $BASE_DIR/kselftest/runner.sh 161 logfile=$logfile 162 run_one $DIR $TEST $test_num 163 EOF 164} 165 166run_in_netns() 167{ 168 local tmplog="/tmp/$(mktemp -u ${BASENAME_TEST}-XXXXXX)" 169 local netns=$(mktemp -u ${BASENAME_TEST}-XXXXXX) 170 local rc 171 172 ip netns add $netns 173 if [ $? -ne 0 ]; then 174 ktap_print_msg "Warning: Create namespace failed for $BASENAME_TEST" 175 ktap_test_fail "$test_num selftests: $DIR: $BASENAME_TEST # Create NS failed" 176 fi 177 ip -n $netns link set lo up 178 179 in_netns $netns &> $tmplog 180 rc=$? 181 182 ip netns del $netns &> /dev/null 183 # Cat the log at once to avoid parallel netns logs. 184 cat $tmplog 185 rm -f $tmplog 186 return $rc 187} 188 189run_many() 190{ 191 DIR="${PWD#${BASE_DIR}/}" 192 test_num=0 193 local rc 194 pids=() 195 196 for TEST in "$@"; do 197 BASENAME_TEST=$(basename $TEST) 198 test_num=$(( test_num + 1 )) 199 if [ -n "$per_test_logging" ]; then 200 logfile="$per_test_log_dir/$BASENAME_TEST" 201 cat /dev/null > "$logfile" 202 fi 203 if [ -n "$RUN_IN_NETNS" ]; then 204 run_in_netns & 205 pids+=($!) 206 else 207 run_one "$DIR" "$TEST" "$test_num" 208 fi 209 done 210 211 # These variables are outputs of ktap_helpers.sh but since we've 212 # run the test in a subprocess we need to update them manually 213 for pid in "${pids[@]}"; do 214 wait "$pid" 215 rc=$? 216 case "$rc" in 217 "$KSFT_PASS") 218 KTAP_CNT_PASS=$((KTAP_CNT_PASS + 1));; 219 "$KSFT_FAIL") 220 KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; 221 "$KSFT_SKIP") 222 KTAP_CNT_SKIP=$((KTAP_CNT_SKIP + 1));; 223 "$KSFT_XFAIL") 224 KTAP_CNT_XFAIL=$((KTAP_CNT_XFAIL + 1));; 225 *) 226 KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; 227 esac 228 done 229} 230