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 55 BASENAME_TEST=$(basename $TEST) 56 57 # Reset any "settings"-file variables. 58 export kselftest_timeout="$kselftest_default_timeout" 59 60 # Safe default if tr not available 61 kselftest_cmd_args_ref="KSELFTEST_ARGS" 62 63 # Optional arguments for this command, possibly defined as an 64 # environment variable built using the test executable in all 65 # uppercase and sanitized substituting non acceptable shell 66 # variable name characters with "_" as in: 67 # 68 # KSELFTEST_<UPPERCASE_SANITIZED_TESTNAME>_ARGS="<options>" 69 # 70 # e.g. 71 # 72 # rtctest --> KSELFTEST_RTCTEST_ARGS="/dev/rtc1" 73 # 74 # cpu-on-off-test.sh --> KSELFTEST_CPU_ON_OFF_TEST_SH_ARGS="-a -p 10" 75 # 76 if [ -n "$TR_CMD" ]; then 77 BASENAME_SANITIZED=$(echo "$BASENAME_TEST" | \ 78 $TR_CMD -d "[:blank:][:cntrl:]" | \ 79 $TR_CMD -c "[:alnum:]_" "_" | \ 80 $TR_CMD [:lower:] [:upper:]) 81 kselftest_cmd_args_ref="KSELFTEST_${BASENAME_SANITIZED}_ARGS" 82 fi 83 84 # Load per-test-directory kselftest "settings" file. 85 settings="$BASE_DIR/$DIR/settings" 86 if [ -r "$settings" ] ; then 87 while read line ; do 88 # Skip comments. 89 if echo "$line" | grep -q '^#'; then 90 continue 91 fi 92 field=$(echo "$line" | cut -d= -f1) 93 value=$(echo "$line" | cut -d= -f2-) 94 eval "kselftest_$field"="$value" 95 done < "$settings" 96 fi 97 98 # Command line timeout overrides the settings file 99 if [ -n "$kselftest_override_timeout" ]; then 100 kselftest_timeout="$kselftest_override_timeout" 101 ktap_print_msg "overriding timeout to $kselftest_timeout" >> "$logfile" 102 else 103 ktap_print_msg "timeout set to $kselftest_timeout" >> "$logfile" 104 fi 105 106 TEST_HDR_MSG="selftests: $DIR: $BASENAME_TEST" 107 echo "# $TEST_HDR_MSG" 108 if [ ! -e "$TEST" ]; then 109 ktap_print_msg "Warning: file $TEST is missing!" 110 ktap_test_fail "$TEST_HDR_MSG" 111 rc=$KSFT_FAIL 112 else 113 if [ -x /usr/bin/stdbuf ]; then 114 stdbuf="/usr/bin/stdbuf --output=L " 115 fi 116 eval kselftest_cmd_args="\$${kselftest_cmd_args_ref:-}" 117 if [ -x "$TEST" ]; then 118 cmd="$stdbuf ./$BASENAME_TEST $kselftest_cmd_args" 119 elif [ -x "./ksft_runner.sh" ]; then 120 cmd="$stdbuf ./ksft_runner.sh ./$BASENAME_TEST" 121 else 122 ktap_print_msg "Warning: file $TEST is not executable" 123 124 if [ $(head -n 1 "$TEST" | cut -c -2) = "#!" ] 125 then 126 interpreter=$(head -n 1 "$TEST" | cut -c 3-) 127 cmd="$stdbuf $interpreter ./$BASENAME_TEST" 128 else 129 ktap_test_fail "$TEST_HDR_MSG" 130 return $KSFT_FAIL 131 fi 132 fi 133 cd `dirname $TEST` > /dev/null 134 (((( tap_timeout "$cmd" 2>&1; echo $? >&3) | 135 tap_prefix >&4) 3>&1) | 136 (read xs; exit $xs)) 4>>"$logfile" 137 rc=$? 138 case "$rc" in 139 "$KSFT_PASS") 140 ktap_test_pass "$TEST_HDR_MSG";; 141 "$KSFT_SKIP") 142 ktap_test_skip "$TEST_HDR_MSG";; 143 "$KSFT_XFAIL") 144 ktap_test_xfail "$TEST_HDR_MSG";; 145 "$timeout_rc") 146 ktap_test_fail "$TEST_HDR_MSG # TIMEOUT $kselftest_timeout seconds";; 147 *) 148 ktap_test_fail "$TEST_HDR_MSG # exit=$rc";; 149 esac 150 cd - >/dev/null 151 fi 152 153 return $rc 154} 155 156in_netns() 157{ 158 local name=$1 159 ip netns exec $name bash <<-EOF 160 BASE_DIR=$BASE_DIR 161 source $BASE_DIR/kselftest/runner.sh 162 logfile=$logfile 163 run_one $DIR $TEST 164 EOF 165} 166 167run_in_netns() 168{ 169 local tmplog="/tmp/$(mktemp -u ${BASENAME_TEST}-XXXXXX)" 170 local netns=$(mktemp -u ${BASENAME_TEST}-XXXXXX) 171 local rc 172 173 ip netns add $netns 174 if [ $? -ne 0 ]; then 175 ktap_print_msg "Warning: Create namespace failed for $BASENAME_TEST" 176 ktap_test_fail "selftests: $DIR: $BASENAME_TEST # Create NS failed" 177 fi 178 ip -n $netns link set lo up 179 180 in_netns $netns &> $tmplog 181 rc=$? 182 183 ip netns del $netns &> /dev/null 184 # Cat the log at once to avoid parallel netns logs. 185 cat $tmplog 186 rm -f $tmplog 187 return $rc 188} 189 190run_many() 191{ 192 DIR="${PWD#${BASE_DIR}/}" 193 local rc 194 pids= 195 196 for TEST in "$@"; do 197 BASENAME_TEST=$(basename $TEST) 198 if [ -n "$per_test_logging" ]; then 199 logfile="$per_test_log_dir/$BASENAME_TEST" 200 cat /dev/null > "$logfile" 201 fi 202 if [ -n "$RUN_IN_NETNS" ]; then 203 run_in_netns & 204 pids="$pids $!" 205 else 206 run_one "$DIR" "$TEST" 207 fi 208 done 209 210 # These variables are outputs of ktap_helpers.sh but since we've 211 # run the test in a subprocess we need to update them manually 212 for pid in $pids; do 213 wait "$pid" 214 rc=$? 215 case "$rc" in 216 "$KSFT_PASS") 217 KTAP_CNT_PASS=$((KTAP_CNT_PASS + 1));; 218 "$KSFT_FAIL") 219 KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; 220 "$KSFT_SKIP") 221 KTAP_CNT_SKIP=$((KTAP_CNT_SKIP + 1));; 222 "$KSFT_XFAIL") 223 KTAP_CNT_XFAIL=$((KTAP_CNT_XFAIL + 1));; 224 *) 225 KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; 226 esac 227 done 228} 229