xref: /kvm-unit-tests/scripts/runtime.bash (revision a481914fd0aa0ccc7eb78238a5d24043b7908ddd)
1: "${RUNTIME_arch_run?}"
2: "${MAX_SMP:=$(getconf _NPROCESSORS_ONLN)}"
3: "${TIMEOUT:=90s}"
4
5PASS() { echo -ne "\e[32mPASS\e[0m"; }
6SKIP() { echo -ne "\e[33mSKIP\e[0m"; }
7FAIL() { echo -ne "\e[31mFAIL\e[0m"; }
8
9extract_summary()
10{
11    local cr=$'\r'
12    tail -3 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
13}
14
15# We assume that QEMU is going to work if it tried to load the kernel
16premature_failure()
17{
18    local log
19
20    log="$(eval "$(get_cmdline _NO_FILE_4Uhere_)" 2>&1)"
21
22    echo "$log" | grep "_NO_FILE_4Uhere_" |
23        grep -q -e "could not \(load\|open\) kernel" -e "error loading" -e "failed to load" &&
24        return 1
25
26    RUNTIME_log_stderr <<< "$log"
27
28    echo "$log"
29    return 0
30}
31
32get_cmdline()
33{
34    local kernel=$1
35    echo "TESTNAME=$testname TIMEOUT=$timeout ACCEL=$accel $RUNTIME_arch_run $kernel -smp $smp $opts"
36}
37
38skip_nodefault()
39{
40    [ "$run_all_tests" = "yes" ] && return 1
41    [ "$KUT_STANDALONE" != "yes" ] && return 0
42
43    while true; do
44        read -r -p "Test marked not to be run by default, are you sure (y/N)? " yn
45        case $yn in
46            "Y" | "y" | "Yes" | "yes")
47                return 1
48                ;;
49            "" | "N" | "n" | "No" | "no" | "q" | "quit" | "exit")
50                return 0
51                ;;
52        esac
53    done
54}
55
56function print_result()
57{
58    local status="$1"
59    local testname="$2"
60    local summary="$3"
61    local reason="$4"
62
63    if [ -z "$reason" ]; then
64        echo "$($status) $testname $summary"
65    else
66        echo "$($status) $testname ($reason)"
67    fi
68}
69
70function find_word()
71{
72    grep -Fq " $1 " <<< " $2 "
73}
74
75function run()
76{
77    local testname="$1"
78    local groups="$2"
79    local smp="$3"
80    local kernel="$4"
81    local opts="$5"
82    local arch="$6"
83    local check="${CHECK:-$7}"
84    local accel="$8"
85    local timeout="${9:-$TIMEOUT}" # unittests.cfg overrides the default
86
87    if [ "${CONFIG_EFI}" == "y" ]; then
88        kernel=${kernel/%.flat/.efi}
89    fi
90
91    if [ -z "$testname" ]; then
92        return
93    fi
94
95    if [ -n "$only_tests" ] && ! find_word "$testname" "$only_tests"; then
96        return
97    fi
98
99    if [ -n "$only_group" ] && ! find_word "$only_group" "$groups"; then
100        return
101    fi
102
103    if [ -z "$GEN_SE_HEADER" ] && find_word "pv-host" "$groups"; then
104        print_result "SKIP" $testname "" "no gen-se-header available for pv-host test"
105        return
106    fi
107
108    if [ -z "$only_group" ] && find_word nodefault "$groups" &&
109            skip_nodefault; then
110        print_result "SKIP" $testname "" "test marked as manual run only"
111        return;
112    fi
113
114    if [ -n "$arch" ] && [ "$arch" != "$ARCH" ]; then
115        print_result "SKIP" $testname "" "$arch only"
116        return 2
117    fi
118
119    if [ -n "$accel" ] && [ -n "$ACCEL" ] && [ "$accel" != "$ACCEL" ]; then
120        print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL"
121        return 2
122    elif [ -n "$ACCEL" ]; then
123        accel="$ACCEL"
124    fi
125
126    # check a file for a particular value before running a test
127    # the check line can contain multiple files to check separated by a space
128    # but each check parameter needs to be of the form <path>=<value>
129    if [ "$check" ]; then
130        # There is no globbing or whitespace allowed in check parameters.
131        # shellcheck disable=SC2206
132        check=($check)
133        for check_param in "${check[@]}"; do
134            path=${check_param%%=*}
135            value=${check_param#*=}
136            if ! [ -f "$path" ] || [ "$(cat $path)" != "$value" ]; then
137                print_result "SKIP" $testname "" "$path not equal to $value"
138                return 2
139            fi
140        done
141    fi
142
143    log=$(premature_failure) && {
144        skip=true
145        if [ "${CONFIG_EFI}" == "y" ]; then
146            if [ "$ARCH" == "x86_64" ] &&
147               [[ "$(tail -1 <<<"$log")" =~ "Dummy Hello World!" ]]; then
148                   skip=false
149            elif [ "$ARCH" == "arm64" ] &&
150               [[ "$(tail -2 <<<"$log" | head -1)" =~ "Dummy Hello World!" ]]; then
151                   skip=false
152            fi
153        fi
154
155        if [ ${skip} == true ]; then
156            print_result "SKIP" $testname "" "$(tail -1 <<<"$log")"
157            return 77
158        fi
159    }
160
161    cmdline=$(get_cmdline $kernel)
162    if find_word "migration" "$groups"; then
163        cmdline="MIGRATION=yes $cmdline"
164    fi
165    if find_word "panic" "$groups"; then
166        cmdline="PANIC=yes $cmdline"
167    fi
168    if [ "$verbose" = "yes" ]; then
169        echo $cmdline
170    fi
171
172    # extra_params in the config file may contain backticks that need to be
173    # expanded, so use eval to start qemu.  Use "> >(foo)" instead of a pipe to
174    # preserve the exit status.
175    summary=$(eval "$cmdline" 2> >(RUNTIME_log_stderr $testname) \
176                             > >(tee >(RUNTIME_log_stdout $testname $kernel) | extract_summary))
177    ret=$?
178    [ "$KUT_STANDALONE" != "yes" ] && echo > >(RUNTIME_log_stdout $testname $kernel)
179
180    if [ $ret -eq 0 ]; then
181        print_result "PASS" $testname "$summary"
182    elif [ $ret -eq 77 ]; then
183        print_result "SKIP" $testname "$summary"
184    elif [ $ret -eq 124 ]; then
185        print_result "FAIL" $testname "" "timeout; duration=$timeout"
186        if [ "$tap_output" = "yes" ]; then
187            echo "not ok TEST_NUMBER - ${testname}: timeout; duration=$timeout" >&3
188        fi
189    elif [ $ret -gt 127 ]; then
190        signame="SIG"$(kill -l $(($ret - 128)))
191        print_result "FAIL" $testname "" "terminated on $signame"
192        if [ "$tap_output" = "yes" ]; then
193            echo "not ok TEST_NUMBER - ${testname}: terminated on $signame" >&3
194        fi
195    elif [ $ret -eq 127 ] && [ "$tap_output" = "yes" ]; then
196        echo "not ok TEST_NUMBER - ${testname}: aborted" >&3
197    else
198        print_result "FAIL" $testname "$summary"
199    fi
200
201    return $ret
202}
203
204#
205# Probe for MAX_SMP, in case it's less than the number of host cpus.
206#
207function probe_maxsmp()
208{
209	local smp
210
211	if smp=$($RUNTIME_arch_run _NO_FILE_4Uhere_ -smp $MAX_SMP |& grep 'SMP CPUs'); then
212		smp=${smp##* }
213		smp=${smp/\(}
214		smp=${smp/\)}
215		echo "Restricting MAX_SMP from ($MAX_SMP) to the max supported ($smp)" >&2
216		MAX_SMP=$smp
217	fi
218}
219