blob: c0a1f8e5a3b16c533ba6f8ab6a906311685fddcb [file] [log] [blame]
Leonardo Sandoval9dfdd1b2020-08-06 17:08:11 -05001#!/usr/bin/env bash
Fathi Boudra422bf772019-12-02 11:10:16 +02002#
Chris Kay23f58692022-11-03 14:01:43 +00003# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
Fathi Boudra422bf772019-12-02 11:10:16 +02004#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8set -e
9
10# Enable job control to have background processes run in their own process
11# group. That way, we can kill a background process group in one go.
12set -m
Fathi Boudra422bf772019-12-02 11:10:16 +020013ci_root="$(readlink -f "$(dirname "$0")/..")"
14source "$ci_root/utils.sh"
15
16artefacts="${artefacts-$workspace/artefacts}"
17
18run_root="$workspace/run"
19pid_dir="$workspace/pids"
20
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000021# This variable avoids graceful termination of the model when
22# launched with the parameter 'bp.pl011_uart0.shutdown_on_eot=1'
23exit_on_model_param=0
24
25# Model exit parameter string
26model_exit_param_string="bp.pl011_uart0.shutdown_on_eot=1"
27
Fathi Boudra422bf772019-12-02 11:10:16 +020028mkdir -p "$pid_dir"
29mkdir -p "$run_root"
30
31kill_and_reap() {
32 local gid
Fathi Boudra422bf772019-12-02 11:10:16 +020033 # Kill an active process. Ignore errors
34 [ "$1" ] || return 0
35 kill -0 "$1" &>/dev/null || return 0
36
Zelalem219df412020-05-17 19:21:20 -050037 # Kill the children
38 kill -- "-$1" &>/dev/null || true
Fathi Boudra422bf772019-12-02 11:10:16 +020039 # Kill the group
Zelalem219df412020-05-17 19:21:20 -050040 { gid="$(awk '{print $5}' < /proc/$1/stat)";} 2>/dev/null || return
41 # For Code Coverage plugin it is needed to propagate
42 # the kill signal to the plugin in order to save
43 # the trace statistics.
44 if [ "${COVERAGE_ON}" == "1" ] || [ -n "$cc_enable" ]; then
45 kill -SIGTERM -- "-$gid" &>/dev/null || true
46 else
47 kill -SIGKILL -- "-$gid" &>/dev/null || true
48 fi
Fathi Boudra422bf772019-12-02 11:10:16 +020049 wait "$gid" &>/dev/null || true
50}
51
52# Perform clean up and ignore errors
53cleanup() {
54 local pid
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000055 local sig
Fathi Boudra422bf772019-12-02 11:10:16 +020056
Fathi Boudra422bf772019-12-02 11:10:16 +020057 pushd "$pid_dir"
58 set +e
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000059
60 sig=${1:-SIGINT}
61 echo "signal received: $sig"
62
63 # Avoid the model termination gracefully when the parameter 'exit_on_model_param'
Harrison Mutai5d66de32022-10-19 11:36:30 +010064 # is set and test if exited successfully.
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000065 if [ "$exit_on_model_param" -eq 0 ] || [ "$sig" != "EXIT" ]; then
66 # Kill all background processes so far and wait for them
67 while read pid; do
68 pid="$(cat $pid)"
69 echo $pid
70 # Forcefully killing model process does not show statistical
71 # data (Host CPU time spent running in User and System). Safely
72 # kill the model by using SIGINT(^C) that helps in printing
73 # statistical data.
74 if [ "$pid" == "$model_pid" ] && [ "${COVERAGE_ON}" != "1" ]; then
75 model_cid=$(pgrep -P "$model_pid" | xargs)
76 # ignore errors
77 kill -SIGINT "$model_cid" &>/dev/null || true
Harrison Mutai5d66de32022-10-19 11:36:30 +010078 # Allow some time to print data, we can't use wait since the process is
79 # a child of the daemonized launch process.
80 sleep 5
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000081 fi
Harrison Mutai5d66de32022-10-19 11:36:30 +010082
83 kill_and_reap "$pid"
84
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000085 done < <(find -name '*.pid')
86 fi
87
Fathi Boudra422bf772019-12-02 11:10:16 +020088 popd
89}
90
91# Launch a program. Have its PID saved in a file with given name with .pid
92# suffix. When the program exits, create a file with .success suffix, or one
93# with .fail if it fails. This function blocks, so the caller must '&' this if
94# they want to continue. Call must wait for $pid_dir/$name.pid to be created
95# should it want to read it.
96launch() {
97 local pid
98
99 "$@" &
100 pid="$!"
101 echo "$pid" > "$pid_dir/${name:?}.pid"
102 if wait "$pid"; then
103 touch "$pid_dir/$name.success"
104 else
105 touch "$pid_dir/$name.fail"
106 fi
107}
108
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000109# Provide signal as an argument to the trap function.
110trap_with_sig() {
111 local func
112
113 func="$1" ; shift
114 for sig ; do
115 trap "$func $sig" "$sig"
116 done
117}
118
Fathi Boudra422bf772019-12-02 11:10:16 +0200119# Cleanup actions
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000120trap_with_sig cleanup SIGINT SIGHUP SIGTERM EXIT
Fathi Boudra422bf772019-12-02 11:10:16 +0200121
122# Prevent xterm windows from untracked terminals from popping up, especially
123# when running locally
124not_upon "$test_run" && export DISPLAY=
125
126# Source variables required for run
127source "$artefacts/env"
128
129echo
130echo "RUNNING: $TEST_CONFIG"
131echo
132
133# Accept BIN_MODE from environment, or default to release. If bin_mode is set
134# and non-empty (intended to be set from command line), that takes precedence.
135pkg_bin_mode="${BIN_MODE:-release}"
136bin_mode="${bin_mode:-$pkg_bin_mode}"
137
Fathi Boudra422bf772019-12-02 11:10:16 +0200138# Whether to display primary UART progress live on the console
139primary_live="${primary_live-$PRIMARY_LIVE}"
140
141# Change directory so that all binaries can be accessed realtive to where they
142# lie
143run_cwd="$artefacts/$bin_mode"
144cd "$run_cwd"
145
146# Source environment for run
147if [ -f "run/env" ]; then
148 source "run/env"
149fi
150
Zelalem1af7a7b2020-08-04 17:34:32 -0500151# Source model environment for run
152if [ -f "run/model_env" ]; then
153 source "run/model_env"
154fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200155# Fail if there was no model path set
156if [ -z "$model_path" ]; then
157 die "No model path set by package!"
158fi
159
160# Launch model with parameters
161model_out="$run_root/model_log.txt"
162run_sh="$run_root/run.sh"
163
Zelalem219df412020-05-17 19:21:20 -0500164
Fathi Boudra422bf772019-12-02 11:10:16 +0200165# Generate run.sh
166echo "$model_path \\" > "$run_sh"
167sed '/^\s*$/d' < model_params | sort | sed 's/^/\t/;s/$/ \\/' >> "$run_sh"
Zelalem219df412020-05-17 19:21:20 -0500168
169if [ "${COVERAGE_ON}" == "1" ]; then
170 # Adding code coverage plugin
Zelalem219df412020-05-17 19:21:20 -0500171 echo -e "\t--plugin $coverage_trace_plugin \\" >> "$run_sh"
172fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200173echo -e "\t\"\$@\"" >> "$run_sh"
174
Zelalem219df412020-05-17 19:21:20 -0500175# Running Reboot/Shutdown tests requires storing the state in non-volatile
176# memory(NVM) across reboot. On FVP, NVM is not persistent across reboot, hence
177# NVM was saved to a file($NVM_file) when running the model using the run.sh
178# shell script.
179# If TFTF Reboot/Shutdown tests are enabled, run the fvp model 10 times by
180# feeding the file containing NVM state generated from the previous run. Note
181# that this file also includes FIP image.
182
183if upon "$run_tftf_reboot_tests" = "1"; then
184 tftf_reboot_tests="$run_root/tftf_reboot_tests.sh"
185
186 # Generate tftf_reboot_tests command. It is similar to run_sh.
187 # The model would run the reboot and shutdown tests 10 times
188 # The uart log file generated by FVP model gets overwritten
189 # across reboots. Copy its contents at the end of the test
190 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
191 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
192 cat <<EOF >>"$tftf_reboot_tests"
193
194for i in {1..10}
195do
196EOF
197 cat "$run_sh" >> "$tftf_reboot_tests"
198 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
199 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
200 cat <<EOF >>"$tftf_reboot_tests"
201done
202EOF
203 #Replace fip.bin with file $NVM_file
204 sed -i 's/fip.bin/'"$NVM_file"'/' "$tftf_reboot_tests"
205
206 echo "TFTF Reboot/Shutdown Tests Enabled"
207 cat "$tftf_reboot_tests" >> "$run_sh"
208 rm "$tftf_reboot_tests"
209fi
210
Fathi Boudra422bf772019-12-02 11:10:16 +0200211echo "Model command line:"
212echo
213cat "$run_sh"
214chmod +x "$run_sh"
215echo
216
217# If it's a test run, skip all the hoops and launch model directly.
218if upon "$test_run"; then
219 "$run_sh" "$@"
220 exit 0
221fi
222
223# For an automated run, export a known variable so that we can identify stale
224# processes spawned by Trusted Firmware CI by inspecting its environment.
225export TRUSTED_FIRMWARE_CI="1"
226
227# Change directory to workspace, as all artifacts paths are relative to
228# that, and launch the model. Have model use no buffering on stdout
229: >"$model_out"
230name="model" launch stdbuf -o0 -e0 "$run_sh" &>"$model_out" &
231wait_count=0
232while :; do
233 if [ -f "$pid_dir/model.pid" ]; then
234 break
235 fi
236 sleep 0.1
237
238 let "wait_count += 1"
239 if [ "$wait_count" -gt 100 ]; then
240 die "Failed to launch model!"
241 fi
242done
Fathi Boudra422bf772019-12-02 11:10:16 +0200243
Zelalem219df412020-05-17 19:21:20 -0500244model_pid="$(cat $pid_dir/model.pid)"
Fathi Boudra422bf772019-12-02 11:10:16 +0200245
246# Start a watchdog to kill ourselves if we wait too long for the model
247# response. Note that this is not the timeout for the whole test, but only for
248# the Model to output port numbers.
249(
250if upon "$jenkins_run"; then
251 # Increase this timeout for a cluster run, as it could take longer if
252 # the load on the Jenkins server is high.
253 model_wait_timeout=120
254else
255 model_wait_timeout=30
256fi
257sleep $model_wait_timeout
258echo "Model wait timeout!"
259kill "$$"
260) &
261watchdog="$!"
262
Chris Kay03ffbe72022-11-17 18:53:50 +0000263ports_output="$(mktempfile)"
264
Fathi Boudra422bf772019-12-02 11:10:16 +0200265# Parse UARTs ports from early model output. Send a SIGSTOP to the model
266# as soon as it outputs all UART ports. This is to prevent the model
267# executing before the expect scripts get a chance to connect to the
268# UART thereby losing messages.
269model_fail=1
270while :; do
Chris Kay03ffbe72022-11-17 18:53:50 +0000271 awk -v "num_uarts=$(get_num_uarts "${run_cwd}")" \
272 -f "$(get_ports_script "${run_cwd}")" "$model_out" > "$ports_output"
273 if [ $(wc -l < "$ports_output") -eq "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200274 kill -SIGSTOP "$model_pid"
275 model_fail=0
276 break
277 fi
278
279 # Bail out if model exited meanwhile
280 if ! kill -0 "$model_pid" &>/dev/null; then
281 echo "Model terminated unexpectedly!"
282 break
283 fi
284done
285
286# Kill the watch dog
287kill_and_reap "$watchdog" || true
288
289# Check the model had failed meanwhile, for some reason
290if [ "$model_fail" -ne 0 ]; then
291 exit 1
292fi
293
Zelalem219df412020-05-17 19:21:20 -0500294if ! [ -x "$(command -v expect)" ]; then
295 echo "Error: Expect is not installed."
296 exit 1
297fi
298
Fathi Boudra422bf772019-12-02 11:10:16 +0200299# The wait loop above exited after model port numbers have been parsed. The
300# script's output is ready to be sourced now.
301declare -a ports
302source "$ports_output"
303rm -f "$ports_output"
Chris Kay03ffbe72022-11-17 18:53:50 +0000304if [ "${#ports[@]}" -ne "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200305 echo "Failed to get UART port numbers"
306 kill_and_reap "$model_pid"
307 unset model_pid
308fi
309
310# Launch expect scripts for all UARTs
311uarts=0
Chris Kay03ffbe72022-11-17 18:53:50 +0000312for u in $(seq 0 $(( "$(get_num_uarts "${run_cwd}")" - 1 )) | tac); do
Fathi Boudra422bf772019-12-02 11:10:16 +0200313 script="run/uart$u/expect"
314 if [ -f "$script" ]; then
315 script="$(cat "$script")"
316 else
317 script=
318 fi
319
320 # Primary UART must have a script
321 if [ -z "$script" ]; then
Chris Kay03ffbe72022-11-17 18:53:50 +0000322 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200323 die "No primary UART script!"
324 else
Zelalem219df412020-05-17 19:21:20 -0500325 echo "Ignoring UART$u (no expect script provided)."
Fathi Boudra422bf772019-12-02 11:10:16 +0200326 continue
327 fi
328 fi
329
330 timeout="run/uart$u/timeout"
331 if [ -f "$timeout" ]; then
332 timeout="$(cat "$timeout")"
333 else
334 timeout=
335 fi
Saul Romerod54b6eb2020-10-20 09:03:08 +0100336 timeout="${timeout-1200}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200337
338 full_log="$run_root/uart${u}_full.txt"
339
Chris Kay03ffbe72022-11-17 18:53:50 +0000340 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200341 star="*"
Fathi Boudra422bf772019-12-02 11:10:16 +0200342 else
343 star=" "
Fathi Boudra422bf772019-12-02 11:10:16 +0200344 fi
345
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600346 uart_name="uart$u"
347
Fathi Boudra422bf772019-12-02 11:10:16 +0200348 # Launch expect after exporting required variables
349 (
350 if [ -f "run/uart$u/env" ]; then
351 set -a
352 source "run/uart$u/env"
353 set +a
354 fi
355
Chris Kay03ffbe72022-11-17 18:53:50 +0000356 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ] && upon "$primary_live"; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200357 uart_port="${ports[$u]}" timeout="$timeout" \
358 name="$uart_name" launch expect -f "$ci_root/expect/$script" | \
359 tee "$full_log"
360 echo
361 else
362 uart_port="${ports[$u]}" timeout="$timeout" \
363 name="$uart_name" launch expect -f "$ci_root/expect/$script" \
364 &>"$full_log"
365 fi
366
367 ) &
368
369 let "uarts += 1"
370 echo "Tracking UART$u$star with $script; timeout $timeout."
371done
Fathi Boudra422bf772019-12-02 11:10:16 +0200372# Wait here long 'enough' for expect scripts to connect to ports; then
373# let the model proceed
374sleep 2
375kill -SIGCONT "$model_pid"
376
377# Wait for all children. Note that the wait below is *not* a timed wait.
378result=0
379
380set +e
381pushd "$pid_dir"
Chris Kay23f58692022-11-03 14:01:43 +0000382
383timeout=3600
384
385echo
386
Fathi Boudra422bf772019-12-02 11:10:16 +0200387while :; do
Chris Kay23f58692022-11-03 14:01:43 +0000388 readarray -d '' all < <(find "${pid_dir}" -name 'uart*.pid' -print0)
389 readarray -d '' succeeded < <(find "${pid_dir}" -name 'uart*.success' -print0)
390 readarray -d '' failed < <(find "${pid_dir}" -name 'uart*.fail' -print0)
Fathi Boudra422bf772019-12-02 11:10:16 +0200391
Chris Kay23f58692022-11-03 14:01:43 +0000392 all=("${all[@]##${pid_dir}/uart}")
393 all=("${all[@]%%.pid}")
394
395 succeeded=("${succeeded[@]##${pid_dir}/uart}")
396 succeeded=("${succeeded[@]%%.success}")
397
398 failed=("${failed[@]##${pid_dir}/uart}")
399 failed=("${failed[@]%%.fail}")
400
401 completed=("${succeeded[@]}" "${failed[@]}")
402
403 readarray -t remaining < <( \
404 comm -23 \
405 <(printf '%s\n' "${all[@]}" | sort) \
406 <(printf '%s\n' "${completed[@]}" | sort) \
407 )
408
409 if [ ${#remaining[@]} = 0 ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200410 break
411 fi
412
Chris Kay23f58692022-11-03 14:01:43 +0000413 echo "Waiting ${timeout}s for ${#remaining[@]} UART(s): ${remaining[@]}"
414
Chris Kay03ffbe72022-11-17 18:53:50 +0000415 if [[ " ${completed[@]} " =~ " $(get_payload_uart "${run_cwd}") " ]]; then
416 echo "- Payload (UART $(get_payload_uart "${run_cwd}")) completed!"
Chris Kay23f58692022-11-03 14:01:43 +0000417
418 for uart in "${remaining[@]}"; do
419 pid=$(cat "${pid_dir}/uart${uart}.pid")
420
421 echo "- Terminating UART ${uart} script (PID ${pid})..."
422
423 kill -SIGINT ${pid} || true # Send Ctrl+C - don't force-kill it!
424 done
Fathi Boudra422bf772019-12-02 11:10:16 +0200425 fi
Chris Kay23f58692022-11-03 14:01:43 +0000426
427 if [ ${timeout} = 0 ]; then
428 echo "- Timeout exceeded! Killing model (PID ${model_pid})..."
429
430 kill_and_reap "${model_pid}"
431 fi
432
433 timeout=$((${timeout} - 5)) && sleep 5
Fathi Boudra422bf772019-12-02 11:10:16 +0200434done
Chris Kay23f58692022-11-03 14:01:43 +0000435
436echo
437
438if [ ${#failed[@]} != 0 ]; then
439 echo "${#failed[@]} UART(s) did not match expectations:"
440 echo
441
442 for uart in "${failed[@]}"; do
443 echo " - UART ${uart}: uart${uart}_full.txt"
444 done
445
446 echo
447
448 result=1
449fi
450
Fathi Boudra422bf772019-12-02 11:10:16 +0200451popd
452
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000453# Capture whether the model is running with the 'exit model parameter' or not.
454exit_on_model_param=$(grep -wc "$model_exit_param_string" "$run_cwd/model_params")
Fathi Boudra422bf772019-12-02 11:10:16 +0200455
456if [ "$result" -eq 0 ]; then
457 echo "Test success!"
458else
459 echo "Test failed!"
460fi
461
462if upon "$jenkins_run"; then
463 echo
464 echo "Artefacts location: $BUILD_URL."
465 echo
466fi
467
468if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "$workspace/run" ]; then
Zelalem219df412020-05-17 19:21:20 -0500469 source "$CI_ROOT/script/send_artefacts.sh" "run"
Fathi Boudra422bf772019-12-02 11:10:16 +0200470fi
471
Fathi Boudra422bf772019-12-02 11:10:16 +0200472
Zelalem219df412020-05-17 19:21:20 -0500473exit "$result"
Fathi Boudra422bf772019-12-02 11:10:16 +0200474# vim: set tw=80 sw=8 noet: