: "${RUNTIME_arch_run?}" : "${MAX_SMP:=$(getconf _NPROCESSORS_ONLN)}" : "${TIMEOUT:=90s}" PASS() { echo -ne "\e[32mPASS\e[0m"; } SKIP() { echo -ne "\e[33mSKIP\e[0m"; } FAIL() { echo -ne "\e[31mFAIL\e[0m"; } extract_summary() { local cr=$'\r' tail -5 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/' } # We assume that QEMU is going to work if it tried to load the kernel premature_failure() { local log log="$(eval "$(get_cmdline _NO_FILE_4Uhere_)" 2>&1)" echo "$log" | grep "_NO_FILE_4Uhere_" | grep -q -e "[Cc]ould not \(load\|open\) kernel" \ -e "error loading" \ -e "failed to load" && return 1 RUNTIME_log_stderr <<< "$log" echo "$log" return 0 } get_cmdline() { local kernel=$1 echo "TESTNAME=$testname TIMEOUT=$timeout MACHINE=$machine ACCEL=$accel $RUNTIME_arch_run $kernel -smp $smp $opts" } skip_nodefault() { [ "$run_all_tests" = "yes" ] && return 1 [ "$KUT_STANDALONE" != "yes" ] && return 0 while true; do read -r -p "Test marked not to be run by default, are you sure (y/N)? " yn case $yn in "Y" | "y" | "Yes" | "yes") return 1 ;; "" | "N" | "n" | "No" | "no" | "q" | "quit" | "exit") return 0 ;; esac done } function print_result() { local status="$1" local testname="$2" local summary="$3" local reason="$4" if [ -z "$reason" ]; then echo "$($status) $testname $summary" else echo "$($status) $testname ($reason)" fi } function find_word() { grep -Fq " $1 " <<< " $2 " } function run() { local testname="$1" local groups="$2" local smp="$3" local kernel="$4" local opts="$5" local arch="$6" local machine="$7" local check="${CHECK:-$8}" local accel="$9" local timeout="${10:-$TIMEOUT}" # unittests.cfg overrides the default if [ "${CONFIG_EFI}" == "y" ]; then kernel=${kernel/%.flat/.efi} fi if [ -z "$testname" ]; then return fi if [ -n "$only_tests" ] && ! find_word "$testname" "$only_tests"; then return fi if [ -n "$only_group" ] && ! find_word "$only_group" "$groups"; then return fi if [ -z "$GEN_SE_HEADER" ] && find_word "pv-host" "$groups"; then print_result "SKIP" $testname "" "no gen-se-header available for pv-host test" return fi if [ -z "$only_group" ] && find_word nodefault "$groups" && skip_nodefault; then print_result "SKIP" $testname "" "test marked as manual run only" return; fi if [ -n "$arch" ] && [ "$arch" != "$ARCH" ]; then print_result "SKIP" $testname "" "$arch only" return 2 fi if [ -n "$machine" ] && [ -n "$MACHINE" ] && [ "$machine" != "$MACHINE" ]; then print_result "SKIP" $testname "" "$machine only" return 2 elif [ -n "$MACHINE" ]; then machine="$MACHINE" fi if [ -n "$accel" ] && [ -n "$ACCEL" ] && [[ ! "$ACCEL" =~ ^$accel(,|$) ]]; then print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL" return 2 elif [ -n "$ACCEL" ]; then accel="$ACCEL" fi # check a file for a particular value before running a test # the check line can contain multiple files to check separated by a space # but each check parameter needs to be of the form <path>=<value> if [ "$check" ]; then # There is no globbing or whitespace allowed in check parameters. # shellcheck disable=SC2206 check=($check) for check_param in "${check[@]}"; do path=${check_param%%=*} value=${check_param#*=} if ! [ -f "$path" ] || [ "$(cat $path)" != "$value" ]; then print_result "SKIP" $testname "" "$path not equal to $value" return 2 fi done fi log=$(premature_failure) && { skip=true if [ "${CONFIG_EFI}" == "y" ]; then if [ "$ARCH" == "x86_64" ] && [[ "$(tail -1 <<<"$log")" =~ "Dummy Hello World!" ]]; then skip=false elif [ "$ARCH" == "arm64" ] && [[ "$(tail -2 <<<"$log" | head -1)" =~ "Dummy Hello World!" ]]; then skip=false fi fi if [ ${skip} == true ]; then print_result "SKIP" $testname "" "$(tail -1 <<<"$log")" return 77 fi } cmdline=$(get_cmdline $kernel) if find_word "migration" "$groups"; then cmdline="MIGRATION=yes $cmdline" fi if find_word "panic" "$groups"; then cmdline="PANIC=yes $cmdline" fi if [ "$verbose" = "yes" ]; then echo $cmdline fi # extra_params in the config file may contain backticks that need to be # expanded, so use eval to start qemu. Use "> >(foo)" instead of a pipe to # preserve the exit status. summary=$(eval "$cmdline" 2> >(RUNTIME_log_stderr $testname) \ > >(tee >(RUNTIME_log_stdout $testname $kernel) | extract_summary)) ret=$? [ "$KUT_STANDALONE" != "yes" ] && echo > >(RUNTIME_log_stdout $testname $kernel) if [ $ret -eq 0 ]; then print_result "PASS" $testname "$summary" elif [ $ret -eq 77 ]; then print_result "SKIP" $testname "$summary" elif [ $ret -eq 124 ]; then print_result "FAIL" $testname "" "timeout; duration=$timeout" if [ "$tap_output" = "yes" ]; then echo "not ok TEST_NUMBER - ${testname}: timeout; duration=$timeout" >&3 fi elif [ $ret -gt 127 ]; then signame="SIG"$(kill -l $(($ret - 128))) print_result "FAIL" $testname "" "terminated on $signame" if [ "$tap_output" = "yes" ]; then echo "not ok TEST_NUMBER - ${testname}: terminated on $signame" >&3 fi elif [ $ret -eq 127 ] && [ "$tap_output" = "yes" ]; then echo "not ok TEST_NUMBER - ${testname}: aborted" >&3 else print_result "FAIL" $testname "$summary" fi return $ret } # # Probe for MAX_SMP, in case it's less than the number of host cpus. # function probe_maxsmp() { local smp if smp=$($RUNTIME_arch_run _NO_FILE_4Uhere_ -smp $MAX_SMP |& grep 'SMP CPUs'); then smp=${smp##* } smp=${smp/\(} smp=${smp/\)} echo "Restricting MAX_SMP from ($MAX_SMP) to the max supported ($smp)" >&2 MAX_SMP=$smp fi }