1#!/bin/ksh
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 2018 Joyent, Inc.
15#
16
17#
18# bhyve test suite driver
19#
20unalias -a
21
22bt_arg0=$(basename $0)
23bt_root="$(cd $(dirname $0)/..; pwd -P)"
24bt_ksh="/usr/bin/ksh"
25bt_outdir=
26bt_keep=
27bt_all=
28bt_tnum=0
29bt_tfail=0
30bt_tsuc=0
31
32function usage
33{
34	typeset msg="$*"
35	[[ -z "$msg" ]] || echo "$msg" 2>&1
36	cat <<USAGE >&2
37Usage: $bt_arg0  [ -o dir ] [ -k ] [ -a | test ... ]
38
39	-o dir		Sets 'dir' as the output directory
40	-a		Runs all tests, ignores tests passed in
41	-k		Keep output from all tests, not just failures
42	-m		mdb binary to test
43USAGE
44	exit 2
45}
46
47function fatal
48{
49	typeset msg="$*"
50	[[ -z "$msg" ]] && msg="failed"
51	echo "$bt_arg0: $msg" >&2
52	exit 1
53}
54
55function setup_outdir
56{
57	bt_outdir="$bt_outdir/$bt_arg0.$$"
58	mkdir -p $bt_outdir || fatal "failed to make output dir $bt_outdir"
59}
60
61function run_single
62{
63	typeset name=$1
64	typeset expect base ext exe command odir res reason
65	typeset iserr
66
67	[[ -z "$name" ]] && fail "missing test to run"
68	base=${name##*/}
69	ext=${base##*.}
70	expect=${base%%.*}
71	odir="$bt_outdir/current"
72	[[ -z "$ext" ]] && fatal "found test without ext: $name"
73	[[ -z "$expect" ]] && fatal "found test without prefix: $name"
74
75	if [[ "$expect" == "err" || "$expect" == "ecreate" ]]; then
76		iserr="yup"
77	else
78		iserr=""
79	fi
80
81	case "$ext" in
82	"ksh")
83		command="$bt_ksh ./$base"
84		;;
85	"exe")
86		command="./$base"
87		;;
88	"out")
89		#
90		# This is the file format for checking output against.
91		#
92		return 0
93		;;
94	*)
95		echo "skipping test $name (unknown extensino)"
96		return 0
97		;;
98	esac
99
100	echo "Executing test $name ... \c"
101	mkdir -p "$odir" >/dev/null || fatal "can't make output directory"
102	cd $(dirname $name) || fatal "failed to enter test directory"
103	$command > "$odir/stdout" 2>"$odir/stderr"
104	res=$?
105	cd - > /dev/null || fatal "failed to leave test directory"
106
107	if [[ -f "$name.out" ]] && \
108	    ! diff "$name.out" "$odir/stdout" >/dev/null; then
109		cp $name.out $odir/$base.out
110		reason="stdout mismatch"
111	elif [[ -n "$iserr" && $res -eq 0 ]]; then
112		reason="test exited $res, not non-zero"
113	elif [[ -z "$iserr" && $res -ne 0 ]]; then
114		reason="test exited $res, not zero"
115	fi
116
117	if [[ -n "$reason" ]]; then
118		echo "$reason"
119		((bt_tfail++))
120		mv "$odir" "$bt_outdir/failure.$bt_tfail" || fatal \
121		    "failed to move test output directory"
122		cp "$name" "$bt_outdir/failure.$bt_tfail/$(basename $name)" || \
123		    fatal "failed to copy test into output directory"
124	else
125		echo "passed"
126		((bt_tsuc++))
127		mv "$odir" "$bt_outdir/success.$bt_tsuc" || fatal \
128		    "failed to move test directory"
129	fi
130
131	((bt_tnum++))
132}
133
134function run_all
135{
136	typeset tests t dir
137
138	tests=$(ls -1 $bt_root/tst/*/*.@(ksh|exe))
139	for t in $tests; do
140		run_single $t
141	done
142}
143
144function welcome
145{
146	cat <<WELCOME
147Starting tests...
148output directory: $bt_outdir
149WELCOME
150}
151
152function cleanup
153{
154	[[ -n "$bt_keep" ]] && return
155	rm -rf "$bt_outdir"/success.* || fatal \
156	     "failed to remove successful test cases"
157	if [[ $bt_tfail -eq 0 ]]; then
158		rmdir "$bt_outdir" || fatal \
159		    "failed to remove test output directory"
160	fi
161}
162
163function goodbye
164{
165	cat <<EOF
166
167-------------
168Results
169-------------
170
171Tests passed: $bt_tsuc
172Tests failed: $bt_tfail
173Tests ran:    $bt_tnum
174
175EOF
176	if [[ $bt_tfail  -eq 0 ]]; then
177		echo "Congrats, some tiny parts of bhyve aren't completely" \
178		    "broken, the tests pass".
179	else
180		echo "Some tests failed, you have some work to do."
181	fi
182}
183
184while getopts ":ahko:m:" c $@; do
185	case "$c" in
186	a)
187		bt_all="y"
188		;;
189	k)
190		bt_keep="y"
191		;;
192	o)
193		bt_outdir="$OPTARG"
194		;;
195	h)
196		usage
197		;;
198	:)
199		usage "option requires an argument -- $OPTARG"
200		;;
201	*)
202		usage "invalid option -- $OPTARG"
203		;;
204	esac
205done
206
207shift $((OPTIND-1))
208
209[[ -z "$bt_all" && $# == 0 ]] && usage "no tests to run"
210
211[[ -z "$bt_outdir" ]] && bt_outdir="$PWD"
212
213setup_outdir
214welcome
215
216if [[ ! -z "$bt_all" ]]; then
217	run_all
218else
219	for t in $@; do
220		[[ -f $t ]] || fatal "cannot find test $t"
221		run_single $t
222	done
223fi
224
225goodbye
226cleanup
227
228#
229# Exit 1 if we have tests that return non-zero
230#
231[[ $bt_tfai -eq 0 ]]
232