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