1#!/bin/bash
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11#
12
13#
14# Copyright 2020 Joyent, Inc.
15# Copyright 2021 Oxide Computer Company
16#
17
18#
19# mdb test driver
20#
21unalias -a
22shopt -s xpg_echo
23#set -o xtrace
24
25mt_arg0=$(basename $0)
26mt_root=$(dirname $0)
27mt_ksh="/usr/bin/ksh"
28mt_mdb="/usr/bin/mdb"
29mt_outdir=
30mt_keep=
31mt_all=
32mt_tests=
33mt_tnum=0
34mt_tfail=0
35mt_tsuc=0
36
37function usage
38{
39	local msg="$*"
40	[[ -z "$msg" ]] || echo "$msg" 2>&1
41	cat <<USAGE >&2
42Usage: $mt_arg0  [ -o dir ] [ -k ] [ -m executable ] [ test ... ]
43
44	-o dir		Sets 'dir' as the output directory
45	-k		Keep output from all tests, not just failures
46	-m		mdb binary to test
47USAGE
48	exit 2
49}
50
51function fatal
52{
53	local msg="$*"
54	[[ -z "$msg" ]] && msg="failed"
55	echo "$mt_arg0: $msg" >&2
56	exit 1
57}
58
59function setup_outdir
60{
61	mt_outdir="$mt_outdir/$mt_arg0.$$"
62	mkdir -p $mt_outdir || fatal "failed to make output dir $mt_outdir"
63}
64
65function run_single
66{
67	local name=$1
68	local expect base ext exe command odir res reason input
69
70	[[ -z "$name" ]] && fail "missing test to run"
71	base=${name##*/}
72	ext=${base##*.}
73	expect=${base%%.*}
74	odir="$mt_outdir/current"
75	[[ -z "$ext" ]] && fatal "found test without ext: $name"
76	[[ -z "$expect" ]] && fatal "found test without prefix: $name"
77
78	case "$ext" in
79	"ksh")
80		command="$mt_ksh $name"
81		;;
82	"mdb")
83		command="$mt_mdb"
84		input="$name"
85		;;
86	"out")
87		#
88		# This is the file format for checking output against.
89		#
90		return 0
91		;;
92	*)
93		echo "skipping test $name (unknown extensino)"
94		return 0
95		;;
96	esac
97
98	echo "Executing test $name ... \c"
99	mkdir -p "$odir" >/dev/null || fatal "can't make output directory"
100	if [[ -z "$input" ]]; then
101		MDB=$mt_mdb ODIR=$odir $command > "$odir/stdout" \
102		    2>"$odir/stderr"
103		res=$?
104	else
105		MDB=$mt_mdb ODIR=$odir $command < $input > "$odir/stdout" \
106		    2>"$odir/stderr"
107		res=$?
108	fi
109
110	if [[ -f "$name.out" ]] && ! diff "$name.out" "$odir/stdout" >/dev/null; then
111		cp $name.out $odir/$base.out
112		reason="stdout mismatch"
113	elif [[ "$expect" == "tst" && $res -ne 0 ]]; then
114		reason="test exited $res, not zero"
115	elif [[ "$expect" == "err" && $res -eq 0 ]]; then
116		reason="test exited $res, not non-zero"
117	fi
118
119	if [[ -n "$reason" ]]; then
120		echo "$reason"
121		((mt_tfail++))
122		mv "$odir" "$mt_outdir/failure.$mt_tfail" || fatal \
123		    "failed to move test output directory"
124		cp "$name" "$mt_outdir/failure.$mt_tfail/test" || fatal \
125		    "failed to copy test into output directory"
126	else
127		echo "passed"
128		((mt_tsuc++))
129		mv "$odir" "$mt_outdir/success.$mt_tsuc" || fatal \
130		    "failed to move test directory"
131	fi
132
133	((mt_tnum++))
134}
135
136function run_all
137{
138	local tests t
139
140	tests=$(find . -type f -name '[tst,err]*.*.[ksh,mdb]*')
141	for t in $tests; do
142		run_single $t
143	done
144}
145
146function welcome
147{
148	cat <<WELCOME
149Starting tests...
150mdbtest target: $mt_mdb
151output directory: $mt_outdir
152WELCOME
153}
154
155function cleanup
156{
157	[[ -n "$mt_keep" ]] && return
158	rm -rf "$mt_outdir"/success.* || fatal \
159	     "failed to remove successful test cases"
160	if [[ $mt_tfail -eq 0 ]]; then
161		rmdir "$mt_outdir" || fatal \
162		    "failed to remove test output directory"
163	fi
164}
165
166function goodbye
167{
168	if [[ $mt_tnum -eq 0 ]]; then
169		fatal "no tests were run, are you in the right directory?"
170	fi
171
172	cat <<EOF
173
174-------------
175Results
176-------------
177
178Tests passed: $mt_tsuc
179Tests failed: $mt_tfail
180Tests ran:    $mt_tnum
181
182EOF
183	if [[ $mt_tfail  -eq 0 ]]; then
184		echo "Congrats, mdb isn't completely broken, the tests pass".
185	else
186		echo "Some tests failed, you have some work to do."
187	fi
188}
189
190while getopts ":hko:m:" c $@; do
191	case "$c" in
192	k)
193		mt_keep="y"
194		;;
195	m)
196		mt_mdb="$OPTARG"
197		;;
198	o)
199		mt_outdir="$OPTARG"
200		;;
201	h)
202		usage
203		;;
204	:)
205		usage "option requires an argument -- $OPTARG"
206		;;
207	*)
208		usage "invalid option -- $OPTARG"
209		;;
210	esac
211done
212
213shift $((OPTIND-1))
214
215[[ $# == 0 ]] && mt_all="y"
216
217[[ -x "$mt_mdb" ]] || fatal "unable to execute mdb binary: $mt_mdb"
218
219[[ -z "$mt_outdir" ]] && mt_outdir=/var/tmp
220
221setup_outdir
222welcome
223
224if [[ ! -z "$mt_all" ]]; then
225	if ! cd "$mt_root"; then
226		fatal "failed to change to test root: $mt_root"
227	fi
228	run_all
229else
230	for t in $@; do
231		[[ -f $t ]] || fatal "cannot find test $t"
232		run_single $t
233	done
234fi
235
236goodbye
237cleanup
238
239#
240# Exit 1 if we have tests that return non-zero
241#
242[[ $mt_tfail -eq 0 ]]
243