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