blob: 346c4d375e5c15fdeee8de2aa90aad7d025431a7 [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'
65 # is set and test if exited successfully.
66 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
79 # Allow some time to print data
80 sleep 2
81 else
82 kill_and_reap "$pid"
83 fi
84 done < <(find -name '*.pid')
85 fi
86
Fathi Boudra422bf772019-12-02 11:10:16 +020087 popd
88}
89
90# Launch a program. Have its PID saved in a file with given name with .pid
91# suffix. When the program exits, create a file with .success suffix, or one
92# with .fail if it fails. This function blocks, so the caller must '&' this if
93# they want to continue. Call must wait for $pid_dir/$name.pid to be created
94# should it want to read it.
95launch() {
96 local pid
97
98 "$@" &
99 pid="$!"
100 echo "$pid" > "$pid_dir/${name:?}.pid"
101 if wait "$pid"; then
102 touch "$pid_dir/$name.success"
103 else
104 touch "$pid_dir/$name.fail"
105 fi
106}
107
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000108# Provide signal as an argument to the trap function.
109trap_with_sig() {
110 local func
111
112 func="$1" ; shift
113 for sig ; do
114 trap "$func $sig" "$sig"
115 done
116}
117
Fathi Boudra422bf772019-12-02 11:10:16 +0200118# Cleanup actions
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000119trap_with_sig cleanup SIGINT SIGHUP SIGTERM EXIT
Fathi Boudra422bf772019-12-02 11:10:16 +0200120
121# Prevent xterm windows from untracked terminals from popping up, especially
122# when running locally
123not_upon "$test_run" && export DISPLAY=
124
125# Source variables required for run
126source "$artefacts/env"
127
128echo
129echo "RUNNING: $TEST_CONFIG"
130echo
131
132# Accept BIN_MODE from environment, or default to release. If bin_mode is set
133# and non-empty (intended to be set from command line), that takes precedence.
134pkg_bin_mode="${BIN_MODE:-release}"
135bin_mode="${bin_mode:-$pkg_bin_mode}"
136
137# Assume 0 is the primary UART to track
138primary_uart=0
139
140# Assume 4 UARTs by default
141num_uarts="${num_uarts:-4}"
142
143# Whether to display primary UART progress live on the console
144primary_live="${primary_live-$PRIMARY_LIVE}"
145
146# Change directory so that all binaries can be accessed realtive to where they
147# lie
148run_cwd="$artefacts/$bin_mode"
149cd "$run_cwd"
150
151# Source environment for run
152if [ -f "run/env" ]; then
153 source "run/env"
154fi
155
Zelalem1af7a7b2020-08-04 17:34:32 -0500156# Source model environment for run
157if [ -f "run/model_env" ]; then
158 source "run/model_env"
159fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200160# Fail if there was no model path set
161if [ -z "$model_path" ]; then
162 die "No model path set by package!"
163fi
164
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600165# Assume primary UART is used by test payload as well
166payload_uart="${payload_uart:-$primary_uart}"
167
Fathi Boudra422bf772019-12-02 11:10:16 +0200168# Launch model with parameters
169model_out="$run_root/model_log.txt"
170run_sh="$run_root/run.sh"
171
Zelalem219df412020-05-17 19:21:20 -0500172
Fathi Boudra422bf772019-12-02 11:10:16 +0200173# Generate run.sh
174echo "$model_path \\" > "$run_sh"
175sed '/^\s*$/d' < model_params | sort | sed 's/^/\t/;s/$/ \\/' >> "$run_sh"
Zelalem219df412020-05-17 19:21:20 -0500176
177if [ "${COVERAGE_ON}" == "1" ]; then
178 # Adding code coverage plugin
179 echo -e "\t-C TRACE.CoverageTrace.trace-file-prefix=$trace_file_prefix \\" >> "$run_sh"
180 echo -e "\t--plugin $coverage_trace_plugin \\" >> "$run_sh"
181fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200182echo -e "\t\"\$@\"" >> "$run_sh"
183
Zelalem219df412020-05-17 19:21:20 -0500184# Running Reboot/Shutdown tests requires storing the state in non-volatile
185# memory(NVM) across reboot. On FVP, NVM is not persistent across reboot, hence
186# NVM was saved to a file($NVM_file) when running the model using the run.sh
187# shell script.
188# If TFTF Reboot/Shutdown tests are enabled, run the fvp model 10 times by
189# feeding the file containing NVM state generated from the previous run. Note
190# that this file also includes FIP image.
191
192if upon "$run_tftf_reboot_tests" = "1"; then
193 tftf_reboot_tests="$run_root/tftf_reboot_tests.sh"
194
195 # Generate tftf_reboot_tests command. It is similar to run_sh.
196 # The model would run the reboot and shutdown tests 10 times
197 # The uart log file generated by FVP model gets overwritten
198 # across reboots. Copy its contents at the end of the test
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"
202
203for i in {1..10}
204do
205EOF
206 cat "$run_sh" >> "$tftf_reboot_tests"
207 echo "cat $uart0_file >> UART0.log" >>"$tftf_reboot_tests"
208 echo "cat $uart1_file >> UART1.log" >>"$tftf_reboot_tests"
209 cat <<EOF >>"$tftf_reboot_tests"
210done
211EOF
212 #Replace fip.bin with file $NVM_file
213 sed -i 's/fip.bin/'"$NVM_file"'/' "$tftf_reboot_tests"
214
215 echo "TFTF Reboot/Shutdown Tests Enabled"
216 cat "$tftf_reboot_tests" >> "$run_sh"
217 rm "$tftf_reboot_tests"
218fi
219
Fathi Boudra422bf772019-12-02 11:10:16 +0200220echo "Model command line:"
221echo
222cat "$run_sh"
223chmod +x "$run_sh"
224echo
225
226# If it's a test run, skip all the hoops and launch model directly.
227if upon "$test_run"; then
228 "$run_sh" "$@"
229 exit 0
230fi
231
232# For an automated run, export a known variable so that we can identify stale
233# processes spawned by Trusted Firmware CI by inspecting its environment.
234export TRUSTED_FIRMWARE_CI="1"
235
236# Change directory to workspace, as all artifacts paths are relative to
237# that, and launch the model. Have model use no buffering on stdout
238: >"$model_out"
239name="model" launch stdbuf -o0 -e0 "$run_sh" &>"$model_out" &
240wait_count=0
241while :; do
242 if [ -f "$pid_dir/model.pid" ]; then
243 break
244 fi
245 sleep 0.1
246
247 let "wait_count += 1"
248 if [ "$wait_count" -gt 100 ]; then
249 die "Failed to launch model!"
250 fi
251done
Fathi Boudra422bf772019-12-02 11:10:16 +0200252
Zelalem219df412020-05-17 19:21:20 -0500253model_pid="$(cat $pid_dir/model.pid)"
Fathi Boudra422bf772019-12-02 11:10:16 +0200254ports_output="$(mktempfile)"
255if not_upon "$ports_script"; then
256 # Default AWK script to parse model ports
257 ports_script="$(mktempfile)"
258 cat <<'EOF' >"$ports_script"
259/terminal_0/ { ports[0] = $NF }
260/terminal_1/ { ports[1] = $NF }
261/terminal_2/ { ports[2] = $NF }
262/terminal_3/ { ports[3] = $NF }
263END {
264 for (i = 0; i < num_uarts; i++) {
265 if (ports[i] != "")
266 print "ports[" i "]=" ports[i]
267 }
268}
269EOF
270fi
271
272# Start a watchdog to kill ourselves if we wait too long for the model
273# response. Note that this is not the timeout for the whole test, but only for
274# the Model to output port numbers.
275(
276if upon "$jenkins_run"; then
277 # Increase this timeout for a cluster run, as it could take longer if
278 # the load on the Jenkins server is high.
279 model_wait_timeout=120
280else
281 model_wait_timeout=30
282fi
283sleep $model_wait_timeout
284echo "Model wait timeout!"
285kill "$$"
286) &
287watchdog="$!"
288
289# Parse UARTs ports from early model output. Send a SIGSTOP to the model
290# as soon as it outputs all UART ports. This is to prevent the model
291# executing before the expect scripts get a chance to connect to the
292# UART thereby losing messages.
293model_fail=1
294while :; do
295 awk -v "num_uarts=$num_uarts" -f "$ports_script" "$model_out" \
296 > "$ports_output"
297 if [ $(wc -l < "$ports_output") -eq "$num_uarts" ]; then
298 kill -SIGSTOP "$model_pid"
299 model_fail=0
300 break
301 fi
302
303 # Bail out if model exited meanwhile
304 if ! kill -0 "$model_pid" &>/dev/null; then
305 echo "Model terminated unexpectedly!"
306 break
307 fi
308done
309
310# Kill the watch dog
311kill_and_reap "$watchdog" || true
312
313# Check the model had failed meanwhile, for some reason
314if [ "$model_fail" -ne 0 ]; then
315 exit 1
316fi
317
Zelalem219df412020-05-17 19:21:20 -0500318if ! [ -x "$(command -v expect)" ]; then
319 echo "Error: Expect is not installed."
320 exit 1
321fi
322
Fathi Boudra422bf772019-12-02 11:10:16 +0200323# The wait loop above exited after model port numbers have been parsed. The
324# script's output is ready to be sourced now.
325declare -a ports
326source "$ports_output"
327rm -f "$ports_output"
328if [ "${#ports[@]}" -ne "$num_uarts" ]; then
329 echo "Failed to get UART port numbers"
330 kill_and_reap "$model_pid"
331 unset model_pid
332fi
333
334# Launch expect scripts for all UARTs
335uarts=0
Zelalem219df412020-05-17 19:21:20 -0500336for u in $(seq 0 $(( $num_uarts - 1 )) | tac); do
Fathi Boudra422bf772019-12-02 11:10:16 +0200337 script="run/uart$u/expect"
338 if [ -f "$script" ]; then
339 script="$(cat "$script")"
340 else
341 script=
342 fi
343
344 # Primary UART must have a script
345 if [ -z "$script" ]; then
346 if [ "$u" = "$primary_uart" ]; then
347 die "No primary UART script!"
348 else
Zelalem219df412020-05-17 19:21:20 -0500349 echo "Ignoring UART$u (no expect script provided)."
Fathi Boudra422bf772019-12-02 11:10:16 +0200350 continue
351 fi
352 fi
353
354 timeout="run/uart$u/timeout"
355 if [ -f "$timeout" ]; then
356 timeout="$(cat "$timeout")"
357 else
358 timeout=
359 fi
Saul Romerod54b6eb2020-10-20 09:03:08 +0100360 timeout="${timeout-1200}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200361
362 full_log="$run_root/uart${u}_full.txt"
363
364 if [ "$u" = "$primary_uart" ]; then
365 star="*"
Fathi Boudra422bf772019-12-02 11:10:16 +0200366 else
367 star=" "
Fathi Boudra422bf772019-12-02 11:10:16 +0200368 fi
369
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600370 uart_name="uart$u"
371
Fathi Boudra422bf772019-12-02 11:10:16 +0200372 # Launch expect after exporting required variables
373 (
374 if [ -f "run/uart$u/env" ]; then
375 set -a
376 source "run/uart$u/env"
377 set +a
378 fi
379
380 if [ "$u" = "$primary_uart" ] && upon "$primary_live"; then
381 uart_port="${ports[$u]}" timeout="$timeout" \
382 name="$uart_name" launch expect -f "$ci_root/expect/$script" | \
383 tee "$full_log"
384 echo
385 else
386 uart_port="${ports[$u]}" timeout="$timeout" \
387 name="$uart_name" launch expect -f "$ci_root/expect/$script" \
388 &>"$full_log"
389 fi
390
391 ) &
392
393 let "uarts += 1"
394 echo "Tracking UART$u$star with $script; timeout $timeout."
395done
Fathi Boudra422bf772019-12-02 11:10:16 +0200396# Wait here long 'enough' for expect scripts to connect to ports; then
397# let the model proceed
398sleep 2
399kill -SIGCONT "$model_pid"
400
401# Wait for all children. Note that the wait below is *not* a timed wait.
402result=0
403
404set +e
405pushd "$pid_dir"
406while :; do
407 wait -n
408
409 # Exit failure if we've any failures
410 if [ "$(wc -l < <(find -name '*.fail'))" -ne 0 ]; then
411 result=1
412 break
413 fi
414
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600415 # We're done if the payload UART exits success
416 if [ -f "$pid_dir/uart$payload_uart.success" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200417 break
418 fi
419done
420popd
421
Manish V Badarkhe359b3ff2020-12-25 18:54:03 +0000422# Capture whether the model is running with the 'exit model parameter' or not.
423exit_on_model_param=$(grep -wc "$model_exit_param_string" "$run_cwd/model_params")
Fathi Boudra422bf772019-12-02 11:10:16 +0200424
425if [ "$result" -eq 0 ]; then
426 echo "Test success!"
427else
428 echo "Test failed!"
429fi
430
431if upon "$jenkins_run"; then
432 echo
433 echo "Artefacts location: $BUILD_URL."
434 echo
435fi
436
437if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "$workspace/run" ]; then
Zelalem219df412020-05-17 19:21:20 -0500438 source "$CI_ROOT/script/send_artefacts.sh" "run"
Fathi Boudra422bf772019-12-02 11:10:16 +0200439fi
440
Fathi Boudra422bf772019-12-02 11:10:16 +0200441
Zelalem219df412020-05-17 19:21:20 -0500442exit "$result"
Fathi Boudra422bf772019-12-02 11:10:16 +0200443# vim: set tw=80 sw=8 noet: