blob: 60ebcb74213a4c5a505a7b0b9d78a55d7fb92b24 [file] [log] [blame]
Leonardo Sandoval9dfdd1b2020-08-06 17:08:11 -05001#!/usr/bin/env bash
Fathi Boudra422bf772019-12-02 11:10:16 +02002#
Boyan Karatotev55a18e92025-07-28 09:17:42 +01003# Copyright (c) 2019-2025, 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# Model exit parameter string
22model_exit_param_string="bp.pl011_uart0.shutdown_on_eot=1"
23
Fathi Boudra422bf772019-12-02 11:10:16 +020024mkdir -p "$pid_dir"
25mkdir -p "$run_root"
26
27kill_and_reap() {
28 local gid
Fathi Boudra422bf772019-12-02 11:10:16 +020029 # Kill an active process. Ignore errors
30 [ "$1" ] || return 0
31 kill -0 "$1" &>/dev/null || return 0
32
Zelalem219df412020-05-17 19:21:20 -050033 # Kill the children
34 kill -- "-$1" &>/dev/null || true
Fathi Boudra422bf772019-12-02 11:10:16 +020035 # Kill the group
Zelalem219df412020-05-17 19:21:20 -050036 { gid="$(awk '{print $5}' < /proc/$1/stat)";} 2>/dev/null || return
37 # For Code Coverage plugin it is needed to propagate
38 # the kill signal to the plugin in order to save
39 # the trace statistics.
40 if [ "${COVERAGE_ON}" == "1" ] || [ -n "$cc_enable" ]; then
41 kill -SIGTERM -- "-$gid" &>/dev/null || true
42 else
43 kill -SIGKILL -- "-$gid" &>/dev/null || true
44 fi
Fathi Boudra422bf772019-12-02 11:10:16 +020045 wait "$gid" &>/dev/null || true
46}
47
48# Perform clean up and ignore errors
49cleanup() {
50 local pid
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000051 local sig
Fathi Boudra422bf772019-12-02 11:10:16 +020052
Fathi Boudra422bf772019-12-02 11:10:16 +020053 pushd "$pid_dir"
54 set +e
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000055
56 sig=${1:-SIGINT}
57 echo "signal received: $sig"
58
Boyan Karatotev40fa01a2025-07-29 14:18:02 +010059 while read pid; do
60 pid="$(cat $pid)"
61 echo $pid
62 # Forcefully killing model process does not show statistical
63 # data (Host CPU time spent running in User and System). Safely
64 # kill the model by using SIGINT(^C) that helps in printing
65 # statistical data.
66 if [ "$pid" == "$model_pid" ] && [ "${COVERAGE_ON}" != "1" ]; then
67 model_cid=$(pgrep -P "$model_pid" | xargs || true)
68 if [ -z "$model_cid" ]; then
69 echo "Model quit by itself. Not killing!"
70 continue
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000071 fi
Harrison Mutai5d66de32022-10-19 11:36:30 +010072
Boyan Karatotev40fa01a2025-07-29 14:18:02 +010073 # ignore errors
74 kill -SIGINT "$model_cid" &>/dev/null || true
75 # Allow some time to print data, we can't use wait since the process is
76 # a child of the daemonized launch process.
77 sleep 5
78 fi
Harrison Mutai5d66de32022-10-19 11:36:30 +010079
Boyan Karatotev40fa01a2025-07-29 14:18:02 +010080 kill_and_reap "$pid"
81
82 done < <(find -name '*.pid')
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000083
Fathi Boudra422bf772019-12-02 11:10:16 +020084 popd
85}
86
87# Launch a program. Have its PID saved in a file with given name with .pid
88# suffix. When the program exits, create a file with .success suffix, or one
89# with .fail if it fails. This function blocks, so the caller must '&' this if
90# they want to continue. Call must wait for $pid_dir/$name.pid to be created
91# should it want to read it.
92launch() {
93 local pid
94
95 "$@" &
96 pid="$!"
97 echo "$pid" > "$pid_dir/${name:?}.pid"
98 if wait "$pid"; then
99 touch "$pid_dir/$name.success"
100 else
101 touch "$pid_dir/$name.fail"
102 fi
103}
104
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000105# Provide signal as an argument to the trap function.
106trap_with_sig() {
107 local func
108
109 func="$1" ; shift
110 for sig ; do
111 trap "$func $sig" "$sig"
112 done
113}
114
Fathi Boudra422bf772019-12-02 11:10:16 +0200115# Cleanup actions
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000116trap_with_sig cleanup SIGINT SIGHUP SIGTERM EXIT
Fathi Boudra422bf772019-12-02 11:10:16 +0200117
118# Prevent xterm windows from untracked terminals from popping up, especially
119# when running locally
120not_upon "$test_run" && export DISPLAY=
121
122# Source variables required for run
123source "$artefacts/env"
124
125echo
126echo "RUNNING: $TEST_CONFIG"
127echo
128
129# Accept BIN_MODE from environment, or default to release. If bin_mode is set
130# and non-empty (intended to be set from command line), that takes precedence.
131pkg_bin_mode="${BIN_MODE:-release}"
132bin_mode="${bin_mode:-$pkg_bin_mode}"
133
Fathi Boudra422bf772019-12-02 11:10:16 +0200134# Whether to display primary UART progress live on the console
135primary_live="${primary_live-$PRIMARY_LIVE}"
136
137# Change directory so that all binaries can be accessed realtive to where they
138# lie
139run_cwd="$artefacts/$bin_mode"
140cd "$run_cwd"
141
142# Source environment for run
143if [ -f "run/env" ]; then
144 source "run/env"
145fi
146
Slava Andrianov192ee172025-06-11 15:40:43 -0500147if [ -v verify_hashes ]; then
148 export verify_hashes=1
149 export artefacts_dir=$run_cwd
150fi
151
Zelalem1af7a7b2020-08-04 17:34:32 -0500152# Source model environment for run
153if [ -f "run/model_env" ]; then
154 source "run/model_env"
155fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200156# Fail if there was no model path set
157if [ -z "$model_path" ]; then
158 die "No model path set by package!"
159fi
160
161# Launch model with parameters
162model_out="$run_root/model_log.txt"
163run_sh="$run_root/run.sh"
164
Zelalem219df412020-05-17 19:21:20 -0500165
Fathi Boudra422bf772019-12-02 11:10:16 +0200166# Generate run.sh
167echo "$model_path \\" > "$run_sh"
168sed '/^\s*$/d' < model_params | sort | sed 's/^/\t/;s/$/ \\/' >> "$run_sh"
Zelalem219df412020-05-17 19:21:20 -0500169
170if [ "${COVERAGE_ON}" == "1" ]; then
171 # Adding code coverage plugin
Zelalem219df412020-05-17 19:21:20 -0500172 echo -e "\t--plugin $coverage_trace_plugin \\" >> "$run_sh"
173fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200174echo -e "\t\"\$@\"" >> "$run_sh"
175
Zelalem219df412020-05-17 19:21:20 -0500176# Running Reboot/Shutdown tests requires storing the state in non-volatile
177# memory(NVM) across reboot. On FVP, NVM is not persistent across reboot, hence
178# NVM was saved to a file($NVM_file) when running the model using the run.sh
179# shell script.
180# If TFTF Reboot/Shutdown tests are enabled, run the fvp model 10 times by
181# feeding the file containing NVM state generated from the previous run. Note
182# that this file also includes FIP image.
183
184if upon "$run_tftf_reboot_tests" = "1"; then
185 tftf_reboot_tests="$run_root/tftf_reboot_tests.sh"
186
187 # Generate tftf_reboot_tests command. It is similar to run_sh.
188 # The model would run the reboot and shutdown tests 10 times
189 # The uart log file generated by FVP model gets overwritten
190 # across reboots. Copy its contents at the end of the test
191 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
192 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
193 cat <<EOF >>"$tftf_reboot_tests"
194
195for i in {1..10}
196do
197EOF
198 cat "$run_sh" >> "$tftf_reboot_tests"
199 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
200 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
201 cat <<EOF >>"$tftf_reboot_tests"
202done
203EOF
204 #Replace fip.bin with file $NVM_file
205 sed -i 's/fip.bin/'"$NVM_file"'/' "$tftf_reboot_tests"
206
207 echo "TFTF Reboot/Shutdown Tests Enabled"
208 cat "$tftf_reboot_tests" >> "$run_sh"
209 rm "$tftf_reboot_tests"
210fi
211
Fathi Boudra422bf772019-12-02 11:10:16 +0200212echo "Model command line:"
213echo
214cat "$run_sh"
215chmod +x "$run_sh"
216echo
217
218# If it's a test run, skip all the hoops and launch model directly.
219if upon "$test_run"; then
220 "$run_sh" "$@"
221 exit 0
222fi
223
224# For an automated run, export a known variable so that we can identify stale
225# processes spawned by Trusted Firmware CI by inspecting its environment.
226export TRUSTED_FIRMWARE_CI="1"
227
228# Change directory to workspace, as all artifacts paths are relative to
229# that, and launch the model. Have model use no buffering on stdout
230: >"$model_out"
231name="model" launch stdbuf -o0 -e0 "$run_sh" &>"$model_out" &
232wait_count=0
233while :; do
234 if [ -f "$pid_dir/model.pid" ]; then
235 break
236 fi
237 sleep 0.1
238
239 let "wait_count += 1"
240 if [ "$wait_count" -gt 100 ]; then
241 die "Failed to launch model!"
242 fi
243done
Fathi Boudra422bf772019-12-02 11:10:16 +0200244
Zelalem219df412020-05-17 19:21:20 -0500245model_pid="$(cat $pid_dir/model.pid)"
Fathi Boudra422bf772019-12-02 11:10:16 +0200246
247# Start a watchdog to kill ourselves if we wait too long for the model
248# response. Note that this is not the timeout for the whole test, but only for
249# the Model to output port numbers.
250(
251if upon "$jenkins_run"; then
252 # Increase this timeout for a cluster run, as it could take longer if
253 # the load on the Jenkins server is high.
254 model_wait_timeout=120
255else
256 model_wait_timeout=30
257fi
258sleep $model_wait_timeout
259echo "Model wait timeout!"
260kill "$$"
261) &
262watchdog="$!"
263
Chris Kay03ffbe72022-11-17 18:53:50 +0000264ports_output="$(mktempfile)"
265
Fathi Boudra422bf772019-12-02 11:10:16 +0200266# Parse UARTs ports from early model output. Send a SIGSTOP to the model
267# as soon as it outputs all UART ports. This is to prevent the model
268# executing before the expect scripts get a chance to connect to the
269# UART thereby losing messages.
270model_fail=1
271while :; do
Chris Kay03ffbe72022-11-17 18:53:50 +0000272 awk -v "num_uarts=$(get_num_uarts "${run_cwd}")" \
273 -f "$(get_ports_script "${run_cwd}")" "$model_out" > "$ports_output"
274 if [ $(wc -l < "$ports_output") -eq "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200275 kill -SIGSTOP "$model_pid"
276 model_fail=0
277 break
278 fi
279
280 # Bail out if model exited meanwhile
281 if ! kill -0 "$model_pid" &>/dev/null; then
282 echo "Model terminated unexpectedly!"
283 break
284 fi
285done
286
287# Kill the watch dog
288kill_and_reap "$watchdog" || true
289
290# Check the model had failed meanwhile, for some reason
291if [ "$model_fail" -ne 0 ]; then
292 exit 1
293fi
294
Zelalem219df412020-05-17 19:21:20 -0500295if ! [ -x "$(command -v expect)" ]; then
296 echo "Error: Expect is not installed."
297 exit 1
298fi
299
Fathi Boudra422bf772019-12-02 11:10:16 +0200300# The wait loop above exited after model port numbers have been parsed. The
301# script's output is ready to be sourced now.
302declare -a ports
303source "$ports_output"
304rm -f "$ports_output"
Chris Kay03ffbe72022-11-17 18:53:50 +0000305if [ "${#ports[@]}" -ne "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200306 echo "Failed to get UART port numbers"
307 kill_and_reap "$model_pid"
308 unset model_pid
309fi
310
311# Launch expect scripts for all UARTs
312uarts=0
Chris Kay03ffbe72022-11-17 18:53:50 +0000313for u in $(seq 0 $(( "$(get_num_uarts "${run_cwd}")" - 1 )) | tac); do
Fathi Boudra422bf772019-12-02 11:10:16 +0200314 script="run/uart$u/expect"
315 if [ -f "$script" ]; then
316 script="$(cat "$script")"
317 else
318 script=
319 fi
320
321 # Primary UART must have a script
322 if [ -z "$script" ]; then
Chris Kay03ffbe72022-11-17 18:53:50 +0000323 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200324 die "No primary UART script!"
325 else
Zelalem219df412020-05-17 19:21:20 -0500326 echo "Ignoring UART$u (no expect script provided)."
Fathi Boudra422bf772019-12-02 11:10:16 +0200327 continue
328 fi
329 fi
330
331 timeout="run/uart$u/timeout"
332 if [ -f "$timeout" ]; then
333 timeout="$(cat "$timeout")"
334 else
335 timeout=
336 fi
Saul Romerod54b6eb2020-10-20 09:03:08 +0100337 timeout="${timeout-1200}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200338
339 full_log="$run_root/uart${u}_full.txt"
340
Chris Kay03ffbe72022-11-17 18:53:50 +0000341 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200342 star="*"
Fathi Boudra422bf772019-12-02 11:10:16 +0200343 else
344 star=" "
Fathi Boudra422bf772019-12-02 11:10:16 +0200345 fi
346
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600347 uart_name="uart$u"
348
Fathi Boudra422bf772019-12-02 11:10:16 +0200349 # Launch expect after exporting required variables
350 (
351 if [ -f "run/uart$u/env" ]; then
352 set -a
353 source "run/uart$u/env"
354 set +a
355 fi
356
Chris Kay03ffbe72022-11-17 18:53:50 +0000357 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ] && upon "$primary_live"; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200358 uart_port="${ports[$u]}" timeout="$timeout" \
359 name="$uart_name" launch expect -f "$ci_root/expect/$script" | \
360 tee "$full_log"
361 echo
362 else
363 uart_port="${ports[$u]}" timeout="$timeout" \
364 name="$uart_name" launch expect -f "$ci_root/expect/$script" \
365 &>"$full_log"
366 fi
367
368 ) &
369
370 let "uarts += 1"
371 echo "Tracking UART$u$star with $script; timeout $timeout."
372done
Fathi Boudra422bf772019-12-02 11:10:16 +0200373# Wait here long 'enough' for expect scripts to connect to ports; then
374# let the model proceed
375sleep 2
376kill -SIGCONT "$model_pid"
377
378# Wait for all children. Note that the wait below is *not* a timed wait.
379result=0
380
381set +e
382pushd "$pid_dir"
Chris Kay23f58692022-11-03 14:01:43 +0000383
384timeout=3600
385
386echo
387
Fathi Boudra422bf772019-12-02 11:10:16 +0200388while :; do
Chris Kay23f58692022-11-03 14:01:43 +0000389 readarray -d '' all < <(find "${pid_dir}" -name 'uart*.pid' -print0)
390 readarray -d '' succeeded < <(find "${pid_dir}" -name 'uart*.success' -print0)
391 readarray -d '' failed < <(find "${pid_dir}" -name 'uart*.fail' -print0)
Fathi Boudra422bf772019-12-02 11:10:16 +0200392
Chris Kay23f58692022-11-03 14:01:43 +0000393 all=("${all[@]##${pid_dir}/uart}")
394 all=("${all[@]%%.pid}")
395
396 succeeded=("${succeeded[@]##${pid_dir}/uart}")
397 succeeded=("${succeeded[@]%%.success}")
398
399 failed=("${failed[@]##${pid_dir}/uart}")
400 failed=("${failed[@]%%.fail}")
401
402 completed=("${succeeded[@]}" "${failed[@]}")
403
404 readarray -t remaining < <( \
405 comm -23 \
406 <(printf '%s\n' "${all[@]}" | sort) \
407 <(printf '%s\n' "${completed[@]}" | sort) \
408 )
409
410 if [ ${#remaining[@]} = 0 ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200411 break
412 fi
413
Chris Kay23f58692022-11-03 14:01:43 +0000414 echo "Waiting ${timeout}s for ${#remaining[@]} UART(s): ${remaining[@]}"
415
Chris Kay03ffbe72022-11-17 18:53:50 +0000416 if [[ " ${completed[@]} " =~ " $(get_payload_uart "${run_cwd}") " ]]; then
417 echo "- Payload (UART $(get_payload_uart "${run_cwd}")) completed!"
Chris Kay23f58692022-11-03 14:01:43 +0000418
419 for uart in "${remaining[@]}"; do
420 pid=$(cat "${pid_dir}/uart${uart}.pid")
421
422 echo "- Terminating UART ${uart} script (PID ${pid})..."
423
424 kill -SIGINT ${pid} || true # Send Ctrl+C - don't force-kill it!
425 done
Fathi Boudra422bf772019-12-02 11:10:16 +0200426 fi
Chris Kay23f58692022-11-03 14:01:43 +0000427
428 if [ ${timeout} = 0 ]; then
429 echo "- Timeout exceeded! Killing model (PID ${model_pid})..."
430
431 kill_and_reap "${model_pid}"
432 fi
433
434 timeout=$((${timeout} - 5)) && sleep 5
Fathi Boudra422bf772019-12-02 11:10:16 +0200435done
Chris Kay23f58692022-11-03 14:01:43 +0000436
437echo
438
439if [ ${#failed[@]} != 0 ]; then
440 echo "${#failed[@]} UART(s) did not match expectations:"
441 echo
442
443 for uart in "${failed[@]}"; do
444 echo " - UART ${uart}: uart${uart}_full.txt"
445 done
446
447 echo
448
449 result=1
450fi
451
Fathi Boudra422bf772019-12-02 11:10:16 +0200452popd
453
Fathi Boudra422bf772019-12-02 11:10:16 +0200454if [ "$result" -eq 0 ]; then
455 echo "Test success!"
456else
457 echo "Test failed!"
458fi
459
460if upon "$jenkins_run"; then
461 echo
462 echo "Artefacts location: $BUILD_URL."
463 echo
464fi
465
466if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "$workspace/run" ]; then
Zelalem219df412020-05-17 19:21:20 -0500467 source "$CI_ROOT/script/send_artefacts.sh" "run"
Fathi Boudra422bf772019-12-02 11:10:16 +0200468fi
469
Fathi Boudra422bf772019-12-02 11:10:16 +0200470
Zelalem219df412020-05-17 19:21:20 -0500471exit "$result"
Fathi Boudra422bf772019-12-02 11:10:16 +0200472# vim: set tw=80 sw=8 noet: