blob: 5db1ef176a35c328bf7d1c45225d3a6d1ef23a91 [file] [log] [blame]
Leonardo Sandoval9dfdd1b2020-08-06 17:08:11 -05001#!/usr/bin/env bash
Fathi Boudra422bf772019-12-02 11:10:16 +02002#
Zelalem219df412020-05-17 19:21:20 -05003# Copyright (c) 2019-2020, 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
139# Assume 0 is the primary UART to track
140primary_uart=0
141
142# Assume 4 UARTs by default
143num_uarts="${num_uarts:-4}"
144
145# Whether to display primary UART progress live on the console
146primary_live="${primary_live-$PRIMARY_LIVE}"
147
148# Change directory so that all binaries can be accessed realtive to where they
149# lie
150run_cwd="$artefacts/$bin_mode"
151cd "$run_cwd"
152
153# Source environment for run
154if [ -f "run/env" ]; then
155 source "run/env"
156fi
157
Zelalem1af7a7b2020-08-04 17:34:32 -0500158# Source model environment for run
159if [ -f "run/model_env" ]; then
160 source "run/model_env"
161fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200162# Fail if there was no model path set
163if [ -z "$model_path" ]; then
164 die "No model path set by package!"
165fi
166
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600167# Assume primary UART is used by test payload as well
168payload_uart="${payload_uart:-$primary_uart}"
169
Fathi Boudra422bf772019-12-02 11:10:16 +0200170# Launch model with parameters
171model_out="$run_root/model_log.txt"
172run_sh="$run_root/run.sh"
173
Zelalem219df412020-05-17 19:21:20 -0500174
Fathi Boudra422bf772019-12-02 11:10:16 +0200175# Generate run.sh
176echo "$model_path \\" > "$run_sh"
177sed '/^\s*$/d' < model_params | sort | sed 's/^/\t/;s/$/ \\/' >> "$run_sh"
Zelalem219df412020-05-17 19:21:20 -0500178
179if [ "${COVERAGE_ON}" == "1" ]; then
180 # Adding code coverage plugin
181 echo -e "\t-C TRACE.CoverageTrace.trace-file-prefix=$trace_file_prefix \\" >> "$run_sh"
182 echo -e "\t--plugin $coverage_trace_plugin \\" >> "$run_sh"
183fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200184echo -e "\t\"\$@\"" >> "$run_sh"
185
Zelalem219df412020-05-17 19:21:20 -0500186# Running Reboot/Shutdown tests requires storing the state in non-volatile
187# memory(NVM) across reboot. On FVP, NVM is not persistent across reboot, hence
188# NVM was saved to a file($NVM_file) when running the model using the run.sh
189# shell script.
190# If TFTF Reboot/Shutdown tests are enabled, run the fvp model 10 times by
191# feeding the file containing NVM state generated from the previous run. Note
192# that this file also includes FIP image.
193
194if upon "$run_tftf_reboot_tests" = "1"; then
195 tftf_reboot_tests="$run_root/tftf_reboot_tests.sh"
196
197 # Generate tftf_reboot_tests command. It is similar to run_sh.
198 # The model would run the reboot and shutdown tests 10 times
199 # The uart log file generated by FVP model gets overwritten
200 # across reboots. Copy its contents at the end of the test
201 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
202 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
203 cat <<EOF >>"$tftf_reboot_tests"
204
205for i in {1..10}
206do
207EOF
208 cat "$run_sh" >> "$tftf_reboot_tests"
209 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
210 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
211 cat <<EOF >>"$tftf_reboot_tests"
212done
213EOF
214 #Replace fip.bin with file $NVM_file
215 sed -i 's/fip.bin/'"$NVM_file"'/' "$tftf_reboot_tests"
216
217 echo "TFTF Reboot/Shutdown Tests Enabled"
218 cat "$tftf_reboot_tests" >> "$run_sh"
219 rm "$tftf_reboot_tests"
220fi
221
Fathi Boudra422bf772019-12-02 11:10:16 +0200222echo "Model command line:"
223echo
224cat "$run_sh"
225chmod +x "$run_sh"
226echo
227
228# If it's a test run, skip all the hoops and launch model directly.
229if upon "$test_run"; then
230 "$run_sh" "$@"
231 exit 0
232fi
233
234# For an automated run, export a known variable so that we can identify stale
235# processes spawned by Trusted Firmware CI by inspecting its environment.
236export TRUSTED_FIRMWARE_CI="1"
237
238# Change directory to workspace, as all artifacts paths are relative to
239# that, and launch the model. Have model use no buffering on stdout
240: >"$model_out"
241name="model" launch stdbuf -o0 -e0 "$run_sh" &>"$model_out" &
242wait_count=0
243while :; do
244 if [ -f "$pid_dir/model.pid" ]; then
245 break
246 fi
247 sleep 0.1
248
249 let "wait_count += 1"
250 if [ "$wait_count" -gt 100 ]; then
251 die "Failed to launch model!"
252 fi
253done
Fathi Boudra422bf772019-12-02 11:10:16 +0200254
Zelalem219df412020-05-17 19:21:20 -0500255model_pid="$(cat $pid_dir/model.pid)"
Fathi Boudra422bf772019-12-02 11:10:16 +0200256ports_output="$(mktempfile)"
257if not_upon "$ports_script"; then
258 # Default AWK script to parse model ports
259 ports_script="$(mktempfile)"
260 cat <<'EOF' >"$ports_script"
261/terminal_0/ { ports[0] = $NF }
262/terminal_1/ { ports[1] = $NF }
263/terminal_2/ { ports[2] = $NF }
264/terminal_3/ { ports[3] = $NF }
265END {
266 for (i = 0; i < num_uarts; i++) {
267 if (ports[i] != "")
268 print "ports[" i "]=" ports[i]
269 }
270}
271EOF
272fi
273
274# Start a watchdog to kill ourselves if we wait too long for the model
275# response. Note that this is not the timeout for the whole test, but only for
276# the Model to output port numbers.
277(
278if upon "$jenkins_run"; then
279 # Increase this timeout for a cluster run, as it could take longer if
280 # the load on the Jenkins server is high.
281 model_wait_timeout=120
282else
283 model_wait_timeout=30
284fi
285sleep $model_wait_timeout
286echo "Model wait timeout!"
287kill "$$"
288) &
289watchdog="$!"
290
291# Parse UARTs ports from early model output. Send a SIGSTOP to the model
292# as soon as it outputs all UART ports. This is to prevent the model
293# executing before the expect scripts get a chance to connect to the
294# UART thereby losing messages.
295model_fail=1
296while :; do
297 awk -v "num_uarts=$num_uarts" -f "$ports_script" "$model_out" \
298 > "$ports_output"
299 if [ $(wc -l < "$ports_output") -eq "$num_uarts" ]; then
300 kill -SIGSTOP "$model_pid"
301 model_fail=0
302 break
303 fi
304
305 # Bail out if model exited meanwhile
306 if ! kill -0 "$model_pid" &>/dev/null; then
307 echo "Model terminated unexpectedly!"
308 break
309 fi
310done
311
312# Kill the watch dog
313kill_and_reap "$watchdog" || true
314
315# Check the model had failed meanwhile, for some reason
316if [ "$model_fail" -ne 0 ]; then
317 exit 1
318fi
319
Zelalem219df412020-05-17 19:21:20 -0500320if ! [ -x "$(command -v expect)" ]; then
321 echo "Error: Expect is not installed."
322 exit 1
323fi
324
Fathi Boudra422bf772019-12-02 11:10:16 +0200325# The wait loop above exited after model port numbers have been parsed. The
326# script's output is ready to be sourced now.
327declare -a ports
328source "$ports_output"
329rm -f "$ports_output"
330if [ "${#ports[@]}" -ne "$num_uarts" ]; then
331 echo "Failed to get UART port numbers"
332 kill_and_reap "$model_pid"
333 unset model_pid
334fi
335
336# Launch expect scripts for all UARTs
337uarts=0
Zelalem219df412020-05-17 19:21:20 -0500338for u in $(seq 0 $(( $num_uarts - 1 )) | tac); do
Fathi Boudra422bf772019-12-02 11:10:16 +0200339 script="run/uart$u/expect"
340 if [ -f "$script" ]; then
341 script="$(cat "$script")"
342 else
343 script=
344 fi
345
346 # Primary UART must have a script
347 if [ -z "$script" ]; then
348 if [ "$u" = "$primary_uart" ]; then
349 die "No primary UART script!"
350 else
Zelalem219df412020-05-17 19:21:20 -0500351 echo "Ignoring UART$u (no expect script provided)."
Fathi Boudra422bf772019-12-02 11:10:16 +0200352 continue
353 fi
354 fi
355
356 timeout="run/uart$u/timeout"
357 if [ -f "$timeout" ]; then
358 timeout="$(cat "$timeout")"
359 else
360 timeout=
361 fi
Saul Romerod54b6eb2020-10-20 09:03:08 +0100362 timeout="${timeout-1200}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200363
364 full_log="$run_root/uart${u}_full.txt"
365
366 if [ "$u" = "$primary_uart" ]; then
367 star="*"
Fathi Boudra422bf772019-12-02 11:10:16 +0200368 else
369 star=" "
Fathi Boudra422bf772019-12-02 11:10:16 +0200370 fi
371
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600372 uart_name="uart$u"
373
Fathi Boudra422bf772019-12-02 11:10:16 +0200374 # Launch expect after exporting required variables
375 (
376 if [ -f "run/uart$u/env" ]; then
377 set -a
378 source "run/uart$u/env"
379 set +a
380 fi
381
382 if [ "$u" = "$primary_uart" ] && upon "$primary_live"; then
383 uart_port="${ports[$u]}" timeout="$timeout" \
384 name="$uart_name" launch expect -f "$ci_root/expect/$script" | \
385 tee "$full_log"
386 echo
387 else
388 uart_port="${ports[$u]}" timeout="$timeout" \
389 name="$uart_name" launch expect -f "$ci_root/expect/$script" \
390 &>"$full_log"
391 fi
392
393 ) &
394
395 let "uarts += 1"
396 echo "Tracking UART$u$star with $script; timeout $timeout."
397done
Fathi Boudra422bf772019-12-02 11:10:16 +0200398# Wait here long 'enough' for expect scripts to connect to ports; then
399# let the model proceed
400sleep 2
401kill -SIGCONT "$model_pid"
402
403# Wait for all children. Note that the wait below is *not* a timed wait.
404result=0
405
406set +e
407pushd "$pid_dir"
408while :; do
409 wait -n
410
411 # Exit failure if we've any failures
412 if [ "$(wc -l < <(find -name '*.fail'))" -ne 0 ]; then
413 result=1
414 break
415 fi
416
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600417 # We're done if the payload UART exits success
418 if [ -f "$pid_dir/uart$payload_uart.success" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200419 break
420 fi
421done
422popd
423
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000424# Capture whether the model is running with the 'exit model parameter' or not.
425exit_on_model_param=$(grep -wc "$model_exit_param_string" "$run_cwd/model_params")
Fathi Boudra422bf772019-12-02 11:10:16 +0200426
427if [ "$result" -eq 0 ]; then
428 echo "Test success!"
429else
430 echo "Test failed!"
431fi
432
433if upon "$jenkins_run"; then
434 echo
435 echo "Artefacts location: $BUILD_URL."
436 echo
437fi
438
439if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "$workspace/run" ]; then
Zelalem219df412020-05-17 19:21:20 -0500440 source "$CI_ROOT/script/send_artefacts.sh" "run"
Fathi Boudra422bf772019-12-02 11:10:16 +0200441fi
442
Fathi Boudra422bf772019-12-02 11:10:16 +0200443
Zelalem219df412020-05-17 19:21:20 -0500444exit "$result"
Fathi Boudra422bf772019-12-02 11:10:16 +0200445# vim: set tw=80 sw=8 noet: