xref: /linux/tools/verification/tests/engine.sh (revision 55ee4b931a7ffedc886175d265dd6e6d08fd4151)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3test_begin() {
4	# Count tests to allow the test harness to double-check if all were
5	# included correctly.
6	ctr=0
7	[ -z "$RV" ] && RV="../rv/rv"
8	[ -z "$RVGEN" ] && RVGEN="python3 ../rvgen"
9	[ -z "$GOLDEN_DIR" ] && GOLDEN_DIR="tests/golden"
10	[ -n "$TEST_COUNT" ] && echo "1..$TEST_COUNT"
11}
12
13failure() {
14	fail=1
15	if [ $# -gt 0 ]; then
16		failbuf+="$1"
17		failbuf+=$'\n'
18	fi
19}
20
21report() {
22	local desc="$1"
23
24	if [ "$fail" -eq 0 ]; then
25		echo "ok $ctr - $desc"
26	else
27		# Add output and exit code as comments in case of failure
28		echo "not ok $ctr - $desc"
29		echo -n "$failbuf"
30		echo "$result" | col -b | while read -r line; do echo "# $line"; done
31		printf "#\n# exit code %s\n" "$exitcode"
32	fi
33}
34
35_check() {
36	local command=$2
37	local expected_exitcode=${3:-0}
38	local expected_output=$4
39	local unexpected_output=$5
40	local all_lines_pattern=$6
41	local patterns="$expected_output $unexpected_output $all_lines_pattern"
42	local bgpid pid
43
44	eval "$TIMEOUT" "$command" &> check_output.$$ &
45	bgpid=$!
46
47	if grep -q "\$pid" <<< "$patterns"; then
48		for _ in {1..30}; do
49			pid=$(pgrep -f "${command%%[|;&>]*}" | tail -n1)
50			[ -n "$pid" ] && break
51			sleep 0.1
52		done
53	fi
54
55	wait $bgpid
56	exitcode=$?
57	result=$(tr -d '\0' < check_output.$$)
58	rm -f check_output.$$
59
60	failbuf=''
61	fail=0
62
63	# Suppress any other error if a needed pid is empty
64	if [ -z "$pid" ] && grep -q "\$pid" <<< "$patterns"; then
65		result=''
66		failure "# Empty pid for $command"
67		return 1
68	fi
69
70	expected_output="${expected_output//\$pid/$pid}"
71	unexpected_output="${unexpected_output//\$pid/$pid}"
72	all_lines_pattern="${all_lines_pattern//\$pid/$pid}"
73
74	# Test if the results matches if requested
75	if [ -n "$expected_output" ] && ! grep -qe "$expected_output" <<< "$result"; then
76		failure "# Output match failed: \"$expected_output\""
77	fi
78
79	if [ -n "$unexpected_output" ] && grep -qe "$unexpected_output" <<< "$result"; then
80		failure "# Output non-match failed: \"$unexpected_output\""
81	fi
82
83	if [ -n "$all_lines_pattern" ] && grep -vqe "$all_lines_pattern" <<< "$result"; then
84		failure "# All-lines pattern failed: \"$all_lines_pattern\""
85	fi
86
87	if [ $exitcode -ne "$expected_exitcode" ]; then
88		failure "# Expected exit code $expected_exitcode"
89	fi
90}
91
92check() {
93	# Simple check: run the command with given arguments and test exit code.
94	# If TEST_COUNT is set, run the test. Otherwise, just count.
95	ctr=$((ctr + 1))
96	if [ -n "$TEST_COUNT" ]; then
97		_check "$@"
98		report "$1"
99	fi
100}
101
102check_if_exists() {
103	# Conditional check that skips if a file or folder doesn't exist
104	local desc=$1
105	local command=$2
106	local file=$3
107	local expected_output=$4
108	local unexpected_output=$5
109	local all_lines_pattern=$6
110
111	ctr=$((ctr + 1))
112	if [ -n "$TEST_COUNT" ]; then
113		if [ ! -e "$file" ]; then
114			echo "ok $ctr - $desc # SKIP file not found: $file"
115		else
116			_check "$desc" "$command" 0 "$expected_output" \
117				"$unexpected_output" "$all_lines_pattern"
118			report "$desc"
119		fi
120	fi
121}
122
123check_and_compare_folder() {
124	# Run command, compare generated folder to golden, and cleanup
125	local desc=$1
126	local command=$2
127	local generated_dir=$3
128	local expected_output=$4
129	local unexpected_output=$5
130	local golden_dir="$GOLDEN_DIR/$generated_dir"
131
132	ctr=$((ctr + 1))
133	if [ -n "$TEST_COUNT" ]; then
134		rm -rf "$generated_dir"
135		_check "$desc" "$command" 0 "$expected_output" "$unexpected_output"
136
137		if [ "$fail" -eq 0 ] && [ ! -d "$generated_dir" ]; then
138			failure "# Generated directory not found: $generated_dir"
139		fi
140
141		if [ "$fail" -ne 0 ]; then
142			:
143		elif ! diff -r "$generated_dir" "$golden_dir" &> /dev/null; then
144			failure "# Directories differ:"
145			failbuf+=$(diff -r "$generated_dir" "$golden_dir" 2>&1 | sed 's/^/#   /')
146			failbuf+=$'\n'
147		fi
148
149		report "$1"
150
151		rm -rf "$generated_dir"
152	fi
153}
154
155set_timeout() {
156	TIMEOUT="timeout -v -k 30s $1"
157}
158
159set_expected_timeout() {
160	TIMEOUT="timeout --preserve-status -k 30s $1"
161}
162
163unset_timeout() {
164	unset TIMEOUT
165}
166
167test_end() {
168	# If running without TEST_COUNT, tests are not actually run, just
169	# counted. In that case, re-run the test with the correct count.
170	[ -z "$TEST_COUNT" ] && TEST_COUNT=$ctr exec bash "$0" || true
171}
172
173# Avoid any environmental discrepancies
174export LC_ALL=C
175unset_timeout
176