xref: /kvm-unit-tests/scripts/runtime.bash (revision 25c4b4b4136a34609d6a10bdcbbdb4cce64b8349)
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 $test_args $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 [ "${CONFIG_EFI}" == "y" ]; then
92        kernel=${kernel/%.flat/.efi}
93    fi
94
95    if [ -z "$testname" ]; then
96        return
97    fi
98
99    if [ -n "$only_tests" ] && ! find_word "$testname" "$only_tests"; then
100        return
101    fi
102
103    if [ -n "$only_group" ] && ! find_word "$only_group" "$groups"; then
104        return
105    fi
106
107    if [ -z "$GEN_SE_HEADER" ] && find_word "pv-host" "$groups"; then
108        print_result "SKIP" $testname "" "no gen-se-header available for pv-host test"
109        return
110    fi
111
112    if [ -z "$only_group" ] && find_word nodefault "$groups" &&
113            skip_nodefault; then
114        print_result "SKIP" $testname "" "test marked as manual run only"
115        return;
116    fi
117
118    if [ -n "$arch" ] && [ "$arch" != "$ARCH" ]; then
119        print_result "SKIP" $testname "" "$arch only"
120        return 2
121    fi
122
123    if [ -n "$machine" ] && [ -n "$MACHINE" ] && [ "$machine" != "$MACHINE" ]; then
124        print_result "SKIP" $testname "" "$machine only"
125        return 2
126    elif [ -n "$MACHINE" ]; then
127        machine="$MACHINE"
128    fi
129
130    if [ -n "$accel" ] && [ -n "$ACCEL" ] && [[ ! "$ACCEL" =~ ^$accel(,|$) ]]; then
131        print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL"
132        return 2
133    elif [ -n "$ACCEL" ]; then
134        accel="$ACCEL"
135    fi
136
137    # check a file for a particular value before running a test
138    # the check line can contain multiple files to check separated by a space
139    # but each check parameter needs to be of the form <path>=<value>
140    if [ "$check" ]; then
141        # There is no globbing or whitespace allowed in check parameters.
142        # shellcheck disable=SC2206
143        check=($check)
144        for check_param in "${check[@]}"; do
145            path=${check_param%%=*}
146            value=${check_param#*=}
147            if ! [ -f "$path" ] || [ "$(cat $path)" != "$value" ]; then
148                print_result "SKIP" $testname "" "$path not equal to $value"
149                return 2
150            fi
151        done
152    fi
153
154    log=$(premature_failure) && {
155        skip=true
156        if [ "${CONFIG_EFI}" == "y" ]; then
157            if [ "$ARCH" == "x86_64" ] &&
158               [[ "$(tail -1 <<<"$log")" =~ "Dummy Hello World!" ]]; then
159                   skip=false
160            elif [ "$ARCH" == "arm64" ] &&
161               [[ "$(tail -2 <<<"$log" | head -1)" =~ "Dummy Hello World!" ]]; then
162                   skip=false
163            fi
164        fi
165
166        if [ ${skip} == true ]; then
167            print_result "SKIP" $testname "" "$(tail -1 <<<"$log")"
168            return 77
169        fi
170    }
171
172    cmdline=$(get_cmdline $kernel)
173    if find_word "migration" "$groups"; then
174        cmdline="MIGRATION=yes $cmdline"
175    fi
176    if find_word "panic" "$groups"; then
177        cmdline="PANIC=yes $cmdline"
178    fi
179    if [ "$verbose" = "yes" ]; then
180        echo $cmdline
181    fi
182
183    # qemu_params/extra_params in the config file may contain backticks that
184    # need to be expanded, so use eval to start qemu.  Use "> >(foo)" instead of
185    # a pipe to preserve the exit status.
186    summary=$(eval "$cmdline" 2> >(RUNTIME_log_stderr $testname) \
187                             > >(tee >(RUNTIME_log_stdout $testname $kernel) | extract_summary))
188    ret=$?
189    [ "$KUT_STANDALONE" != "yes" ] && echo > >(RUNTIME_log_stdout $testname $kernel)
190
191    if [ $ret -eq 0 ]; then
192        print_result "PASS" $testname "$summary"
193    elif [ $ret -eq 77 ]; then
194        print_result "SKIP" $testname "$summary"
195    elif [ $ret -eq 124 ]; then
196        print_result "FAIL" $testname "" "timeout; duration=$timeout"
197        if [ "$tap_output" = "yes" ]; then
198            echo "not ok TEST_NUMBER - ${testname}: timeout; duration=$timeout" >&3
199        fi
200    elif [ $ret -gt 127 ]; then
201        signame="SIG"$(kill -l $(($ret - 128)))
202        print_result "FAIL" $testname "" "terminated on $signame"
203        if [ "$tap_output" = "yes" ]; then
204            echo "not ok TEST_NUMBER - ${testname}: terminated on $signame" >&3
205        fi
206    elif [ $ret -eq 127 ] && [ "$tap_output" = "yes" ]; then
207        echo "not ok TEST_NUMBER - ${testname}: aborted" >&3
208    else
209        print_result "FAIL" $testname "$summary"
210    fi
211
212    return $ret
213}
214
215#
216# Probe for MAX_SMP, in case it's less than the number of host cpus.
217#
218function probe_maxsmp()
219{
220	local smp
221
222	if smp=$($RUNTIME_arch_run _NO_FILE_4Uhere_ -smp $MAX_SMP |& grep 'SMP CPUs'); then
223		smp=${smp##* }
224		smp=${smp/\(}
225		smp=${smp/\)}
226		echo "Restricting MAX_SMP from ($MAX_SMP) to the max supported ($smp)" >&2
227		MAX_SMP=$smp
228	fi
229}
230