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