blob: 26cb745e46c0de28cf1b3e5ebcb16db2cb7f2644 [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
13
14ci_root="$(readlink -f "$(dirname "$0")/..")"
15source "$ci_root/utils.sh"
16
17artefacts="${artefacts-$workspace/artefacts}"
18
19run_root="$workspace/run"
20pid_dir="$workspace/pids"
21
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000022# This variable avoids graceful termination of the model when
23# launched with the parameter 'bp.pl011_uart0.shutdown_on_eot=1'
24exit_on_model_param=0
25
26# Model exit parameter string
27model_exit_param_string="bp.pl011_uart0.shutdown_on_eot=1"
28
Fathi Boudra422bf772019-12-02 11:10:16 +020029mkdir -p "$pid_dir"
30mkdir -p "$run_root"
31
32kill_and_reap() {
33 local gid
Fathi Boudra422bf772019-12-02 11:10:16 +020034 # Kill an active process. Ignore errors
35 [ "$1" ] || return 0
36 kill -0 "$1" &>/dev/null || return 0
37
Zelalem219df412020-05-17 19:21:20 -050038 # Kill the children
39 kill -- "-$1" &>/dev/null || true
Fathi Boudra422bf772019-12-02 11:10:16 +020040 # Kill the group
Zelalem219df412020-05-17 19:21:20 -050041 { gid="$(awk '{print $5}' < /proc/$1/stat)";} 2>/dev/null || return
42 # For Code Coverage plugin it is needed to propagate
43 # the kill signal to the plugin in order to save
44 # the trace statistics.
45 if [ "${COVERAGE_ON}" == "1" ] || [ -n "$cc_enable" ]; then
46 kill -SIGTERM -- "-$gid" &>/dev/null || true
47 else
48 kill -SIGKILL -- "-$gid" &>/dev/null || true
49 fi
Fathi Boudra422bf772019-12-02 11:10:16 +020050 wait "$gid" &>/dev/null || true
51}
52
53# Perform clean up and ignore errors
54cleanup() {
55 local pid
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000056 local sig
Fathi Boudra422bf772019-12-02 11:10:16 +020057
Fathi Boudra422bf772019-12-02 11:10:16 +020058 pushd "$pid_dir"
59 set +e
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000060
61 sig=${1:-SIGINT}
62 echo "signal received: $sig"
63
64 # Avoid the model termination gracefully when the parameter 'exit_on_model_param'
Harrison Mutai5d66de32022-10-19 11:36:30 +010065 # is set and test if exited successfully.
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000066 if [ "$exit_on_model_param" -eq 0 ] || [ "$sig" != "EXIT" ]; then
67 # Kill all background processes so far and wait for them
68 while read pid; do
69 pid="$(cat $pid)"
70 echo $pid
71 # Forcefully killing model process does not show statistical
72 # data (Host CPU time spent running in User and System). Safely
73 # kill the model by using SIGINT(^C) that helps in printing
74 # statistical data.
75 if [ "$pid" == "$model_pid" ] && [ "${COVERAGE_ON}" != "1" ]; then
76 model_cid=$(pgrep -P "$model_pid" | xargs)
77 # ignore errors
78 kill -SIGINT "$model_cid" &>/dev/null || true
Harrison Mutai5d66de32022-10-19 11:36:30 +010079 # Allow some time to print data, we can't use wait since the process is
80 # a child of the daemonized launch process.
81 sleep 5
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000082 fi
Harrison Mutai5d66de32022-10-19 11:36:30 +010083
84 kill_and_reap "$pid"
85
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +000086 done < <(find -name '*.pid')
87 fi
88
Fathi Boudra422bf772019-12-02 11:10:16 +020089 popd
90}
91
92# Launch a program. Have its PID saved in a file with given name with .pid
93# suffix. When the program exits, create a file with .success suffix, or one
94# with .fail if it fails. This function blocks, so the caller must '&' this if
95# they want to continue. Call must wait for $pid_dir/$name.pid to be created
96# should it want to read it.
97launch() {
98 local pid
99
100 "$@" &
101 pid="$!"
102 echo "$pid" > "$pid_dir/${name:?}.pid"
103 if wait "$pid"; then
104 touch "$pid_dir/$name.success"
105 else
106 touch "$pid_dir/$name.fail"
107 fi
108}
109
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000110# Provide signal as an argument to the trap function.
111trap_with_sig() {
112 local func
113
114 func="$1" ; shift
115 for sig ; do
116 trap "$func $sig" "$sig"
117 done
118}
119
Fathi Boudra422bf772019-12-02 11:10:16 +0200120# Cleanup actions
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000121trap_with_sig cleanup SIGINT SIGHUP SIGTERM EXIT
Fathi Boudra422bf772019-12-02 11:10:16 +0200122
123# Prevent xterm windows from untracked terminals from popping up, especially
124# when running locally
125not_upon "$test_run" && export DISPLAY=
126
127# Source variables required for run
128source "$artefacts/env"
129
130echo
131echo "RUNNING: $TEST_CONFIG"
132echo
133
134# Accept BIN_MODE from environment, or default to release. If bin_mode is set
135# and non-empty (intended to be set from command line), that takes precedence.
136pkg_bin_mode="${BIN_MODE:-release}"
137bin_mode="${bin_mode:-$pkg_bin_mode}"
138
Fathi Boudra422bf772019-12-02 11:10:16 +0200139# Whether to display primary UART progress live on the console
140primary_live="${primary_live-$PRIMARY_LIVE}"
141
142# Change directory so that all binaries can be accessed realtive to where they
143# lie
144run_cwd="$artefacts/$bin_mode"
145cd "$run_cwd"
146
147# Source environment for run
148if [ -f "run/env" ]; then
149 source "run/env"
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
172 echo -e "\t-C TRACE.CoverageTrace.trace-file-prefix=$trace_file_prefix \\" >> "$run_sh"
173 echo -e "\t--plugin $coverage_trace_plugin \\" >> "$run_sh"
174fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200175echo -e "\t\"\$@\"" >> "$run_sh"
176
Zelalem219df412020-05-17 19:21:20 -0500177# Running Reboot/Shutdown tests requires storing the state in non-volatile
178# memory(NVM) across reboot. On FVP, NVM is not persistent across reboot, hence
179# NVM was saved to a file($NVM_file) when running the model using the run.sh
180# shell script.
181# If TFTF Reboot/Shutdown tests are enabled, run the fvp model 10 times by
182# feeding the file containing NVM state generated from the previous run. Note
183# that this file also includes FIP image.
184
185if upon "$run_tftf_reboot_tests" = "1"; then
186 tftf_reboot_tests="$run_root/tftf_reboot_tests.sh"
187
188 # Generate tftf_reboot_tests command. It is similar to run_sh.
189 # The model would run the reboot and shutdown tests 10 times
190 # The uart log file generated by FVP model gets overwritten
191 # across reboots. Copy its contents at the end of the test
192 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
193 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
194 cat <<EOF >>"$tftf_reboot_tests"
195
196for i in {1..10}
197do
198EOF
199 cat "$run_sh" >> "$tftf_reboot_tests"
200 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
201 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
202 cat <<EOF >>"$tftf_reboot_tests"
203done
204EOF
205 #Replace fip.bin with file $NVM_file
206 sed -i 's/fip.bin/'"$NVM_file"'/' "$tftf_reboot_tests"
207
208 echo "TFTF Reboot/Shutdown Tests Enabled"
209 cat "$tftf_reboot_tests" >> "$run_sh"
210 rm "$tftf_reboot_tests"
211fi
212
Fathi Boudra422bf772019-12-02 11:10:16 +0200213echo "Model command line:"
214echo
215cat "$run_sh"
216chmod +x "$run_sh"
217echo
218
219# If it's a test run, skip all the hoops and launch model directly.
220if upon "$test_run"; then
221 "$run_sh" "$@"
222 exit 0
223fi
224
225# For an automated run, export a known variable so that we can identify stale
226# processes spawned by Trusted Firmware CI by inspecting its environment.
227export TRUSTED_FIRMWARE_CI="1"
228
229# Change directory to workspace, as all artifacts paths are relative to
230# that, and launch the model. Have model use no buffering on stdout
231: >"$model_out"
232name="model" launch stdbuf -o0 -e0 "$run_sh" &>"$model_out" &
233wait_count=0
234while :; do
235 if [ -f "$pid_dir/model.pid" ]; then
236 break
237 fi
238 sleep 0.1
239
240 let "wait_count += 1"
241 if [ "$wait_count" -gt 100 ]; then
242 die "Failed to launch model!"
243 fi
244done
Fathi Boudra422bf772019-12-02 11:10:16 +0200245
Zelalem219df412020-05-17 19:21:20 -0500246model_pid="$(cat $pid_dir/model.pid)"
Fathi Boudra422bf772019-12-02 11:10:16 +0200247
248# Start a watchdog to kill ourselves if we wait too long for the model
249# response. Note that this is not the timeout for the whole test, but only for
250# the Model to output port numbers.
251(
252if upon "$jenkins_run"; then
253 # Increase this timeout for a cluster run, as it could take longer if
254 # the load on the Jenkins server is high.
255 model_wait_timeout=120
256else
257 model_wait_timeout=30
258fi
259sleep $model_wait_timeout
260echo "Model wait timeout!"
261kill "$$"
262) &
263watchdog="$!"
264
Chris Kay03ffbe72022-11-17 18:53:50 +0000265ports_output="$(mktempfile)"
266
Fathi Boudra422bf772019-12-02 11:10:16 +0200267# Parse UARTs ports from early model output. Send a SIGSTOP to the model
268# as soon as it outputs all UART ports. This is to prevent the model
269# executing before the expect scripts get a chance to connect to the
270# UART thereby losing messages.
271model_fail=1
272while :; do
Chris Kay03ffbe72022-11-17 18:53:50 +0000273 awk -v "num_uarts=$(get_num_uarts "${run_cwd}")" \
274 -f "$(get_ports_script "${run_cwd}")" "$model_out" > "$ports_output"
275 if [ $(wc -l < "$ports_output") -eq "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200276 kill -SIGSTOP "$model_pid"
277 model_fail=0
278 break
279 fi
280
281 # Bail out if model exited meanwhile
282 if ! kill -0 "$model_pid" &>/dev/null; then
283 echo "Model terminated unexpectedly!"
284 break
285 fi
286done
287
288# Kill the watch dog
289kill_and_reap "$watchdog" || true
290
291# Check the model had failed meanwhile, for some reason
292if [ "$model_fail" -ne 0 ]; then
293 exit 1
294fi
295
Zelalem219df412020-05-17 19:21:20 -0500296if ! [ -x "$(command -v expect)" ]; then
297 echo "Error: Expect is not installed."
298 exit 1
299fi
300
Fathi Boudra422bf772019-12-02 11:10:16 +0200301# The wait loop above exited after model port numbers have been parsed. The
302# script's output is ready to be sourced now.
303declare -a ports
304source "$ports_output"
305rm -f "$ports_output"
Chris Kay03ffbe72022-11-17 18:53:50 +0000306if [ "${#ports[@]}" -ne "$(get_num_uarts "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200307 echo "Failed to get UART port numbers"
308 kill_and_reap "$model_pid"
309 unset model_pid
310fi
311
312# Launch expect scripts for all UARTs
313uarts=0
Chris Kay03ffbe72022-11-17 18:53:50 +0000314for u in $(seq 0 $(( "$(get_num_uarts "${run_cwd}")" - 1 )) | tac); do
Fathi Boudra422bf772019-12-02 11:10:16 +0200315 script="run/uart$u/expect"
316 if [ -f "$script" ]; then
317 script="$(cat "$script")"
318 else
319 script=
320 fi
321
322 # Primary UART must have a script
323 if [ -z "$script" ]; then
Chris Kay03ffbe72022-11-17 18:53:50 +0000324 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200325 die "No primary UART script!"
326 else
Zelalem219df412020-05-17 19:21:20 -0500327 echo "Ignoring UART$u (no expect script provided)."
Fathi Boudra422bf772019-12-02 11:10:16 +0200328 continue
329 fi
330 fi
331
332 timeout="run/uart$u/timeout"
333 if [ -f "$timeout" ]; then
334 timeout="$(cat "$timeout")"
335 else
336 timeout=
337 fi
Saul Romerod54b6eb2020-10-20 09:03:08 +0100338 timeout="${timeout-1200}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200339
340 full_log="$run_root/uart${u}_full.txt"
341
Chris Kay03ffbe72022-11-17 18:53:50 +0000342 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200343 star="*"
Fathi Boudra422bf772019-12-02 11:10:16 +0200344 else
345 star=" "
Fathi Boudra422bf772019-12-02 11:10:16 +0200346 fi
347
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600348 uart_name="uart$u"
349
Fathi Boudra422bf772019-12-02 11:10:16 +0200350 # Launch expect after exporting required variables
351 (
352 if [ -f "run/uart$u/env" ]; then
353 set -a
354 source "run/uart$u/env"
355 set +a
356 fi
357
Chris Kay03ffbe72022-11-17 18:53:50 +0000358 if [ "$u" = "$(get_primary_uart "${run_cwd}")" ] && upon "$primary_live"; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200359 uart_port="${ports[$u]}" timeout="$timeout" \
360 name="$uart_name" launch expect -f "$ci_root/expect/$script" | \
361 tee "$full_log"
362 echo
363 else
364 uart_port="${ports[$u]}" timeout="$timeout" \
365 name="$uart_name" launch expect -f "$ci_root/expect/$script" \
366 &>"$full_log"
367 fi
368
369 ) &
370
371 let "uarts += 1"
372 echo "Tracking UART$u$star with $script; timeout $timeout."
373done
Fathi Boudra422bf772019-12-02 11:10:16 +0200374# Wait here long 'enough' for expect scripts to connect to ports; then
375# let the model proceed
376sleep 2
377kill -SIGCONT "$model_pid"
378
379# Wait for all children. Note that the wait below is *not* a timed wait.
380result=0
381
382set +e
383pushd "$pid_dir"
Chris Kay23f58692022-11-03 14:01:43 +0000384
385timeout=3600
386
387echo
388
Fathi Boudra422bf772019-12-02 11:10:16 +0200389while :; do
Chris Kay23f58692022-11-03 14:01:43 +0000390 readarray -d '' all < <(find "${pid_dir}" -name 'uart*.pid' -print0)
391 readarray -d '' succeeded < <(find "${pid_dir}" -name 'uart*.success' -print0)
392 readarray -d '' failed < <(find "${pid_dir}" -name 'uart*.fail' -print0)
Fathi Boudra422bf772019-12-02 11:10:16 +0200393
Chris Kay23f58692022-11-03 14:01:43 +0000394 all=("${all[@]##${pid_dir}/uart}")
395 all=("${all[@]%%.pid}")
396
397 succeeded=("${succeeded[@]##${pid_dir}/uart}")
398 succeeded=("${succeeded[@]%%.success}")
399
400 failed=("${failed[@]##${pid_dir}/uart}")
401 failed=("${failed[@]%%.fail}")
402
403 completed=("${succeeded[@]}" "${failed[@]}")
404
405 readarray -t remaining < <( \
406 comm -23 \
407 <(printf '%s\n' "${all[@]}" | sort) \
408 <(printf '%s\n' "${completed[@]}" | sort) \
409 )
410
411 if [ ${#remaining[@]} = 0 ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200412 break
413 fi
414
Chris Kay23f58692022-11-03 14:01:43 +0000415 echo "Waiting ${timeout}s for ${#remaining[@]} UART(s): ${remaining[@]}"
416
Chris Kay03ffbe72022-11-17 18:53:50 +0000417 if [[ " ${completed[@]} " =~ " $(get_payload_uart "${run_cwd}") " ]]; then
418 echo "- Payload (UART $(get_payload_uart "${run_cwd}")) completed!"
Chris Kay23f58692022-11-03 14:01:43 +0000419
420 for uart in "${remaining[@]}"; do
421 pid=$(cat "${pid_dir}/uart${uart}.pid")
422
423 echo "- Terminating UART ${uart} script (PID ${pid})..."
424
425 kill -SIGINT ${pid} || true # Send Ctrl+C - don't force-kill it!
426 done
Fathi Boudra422bf772019-12-02 11:10:16 +0200427 fi
Chris Kay23f58692022-11-03 14:01:43 +0000428
429 if [ ${timeout} = 0 ]; then
430 echo "- Timeout exceeded! Killing model (PID ${model_pid})..."
431
432 kill_and_reap "${model_pid}"
433 fi
434
435 timeout=$((${timeout} - 5)) && sleep 5
Fathi Boudra422bf772019-12-02 11:10:16 +0200436done
Chris Kay23f58692022-11-03 14:01:43 +0000437
438echo
439
440if [ ${#failed[@]} != 0 ]; then
441 echo "${#failed[@]} UART(s) did not match expectations:"
442 echo
443
444 for uart in "${failed[@]}"; do
445 echo " - UART ${uart}: uart${uart}_full.txt"
446 done
447
448 echo
449
450 result=1
451fi
452
Fathi Boudra422bf772019-12-02 11:10:16 +0200453popd
454
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000455# Capture whether the model is running with the 'exit model parameter' or not.
456exit_on_model_param=$(grep -wc "$model_exit_param_string" "$run_cwd/model_params")
Fathi Boudra422bf772019-12-02 11:10:16 +0200457
458if [ "$result" -eq 0 ]; then
459 echo "Test success!"
460else
461 echo "Test failed!"
462fi
463
464if upon "$jenkins_run"; then
465 echo
466 echo "Artefacts location: $BUILD_URL."
467 echo
468fi
469
470if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "$workspace/run" ]; then
Zelalem219df412020-05-17 19:21:20 -0500471 source "$CI_ROOT/script/send_artefacts.sh" "run"
Fathi Boudra422bf772019-12-02 11:10:16 +0200472fi
473
Fathi Boudra422bf772019-12-02 11:10:16 +0200474
Zelalem219df412020-05-17 19:21:20 -0500475exit "$result"
Fathi Boudra422bf772019-12-02 11:10:16 +0200476# vim: set tw=80 sw=8 noet: