xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/channel_program/channel_common.kshlib (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1# SPDX-License-Identifier: CDDL-1.0
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 (c) 2016, 2017 by Delphix. All rights reserved.
15#
16
17. $STF_SUITE/include/libtest.shlib
18
19ZCP_ROOT=$STF_SUITE/tests/functional/channel_program
20
21#
22# Note: In case of failure (log_fail) in this function
23# we delete the file passed as <input file> so the
24# test suite doesn't leak temp files on failures. So it
25# is expected that <input file> is a temp file and not
26# an installed file.
27#
28# <exitcode> <expected error string> <input file> <zfs program args>
29# e.g. log_program 0 "" tmp.7a12V $POOL foo.zcp arg1 arg2
30function log_program
31{
32	typeset expectexit=$1
33	shift
34	typeset expecterror=$1
35	shift
36	typeset tmpin=$1
37	shift
38	typeset cmdargs=$@ tmpout=$(mktemp) tmperr=$(mktemp)
39
40	# Expected output/error filename is the same as the .zcp name
41	typeset basename
42	if [[ $2 != "-" ]]; then
43		basename=${2%.*}
44	fi
45
46	log_note "running: zfs program $cmdargs:"
47
48	zfs program $cmdargs >$tmpout 2>$tmperr
49	typeset ret=$?
50
51	log_note $'input:\n'"$(<$tmpin)"
52	log_note $'output:\n'"$(<$tmpout)"
53	log_note $'error:\n'"$(<$tmperr)"
54	log_note "ret: $ret"
55
56	#
57	# Verify correct return value
58	#
59	if [[ $ret -ne $expectexit ]]; then
60		rm $tmpout $tmperr $tmpin
61		log_fail "return mismatch: expected $expectexit, got $ret"
62	fi
63
64	#
65	# Check the output or reported error for successful or error returns,
66	# respectively.
67	#
68	if [[ -f "$basename.out" ]] && [[ $expectexit -eq 0 ]]; then
69		if ! outdiff=$(diff "$basename.out" "$tmpout"); then
70			output=$(<$tmpout)
71			rm $tmpout $tmperr $tmpin
72			log_fail $'Output mismatch. Expected:\n' \
73				"$(<$basename.out)"$'\nBut got:\n'"$output"$'\n' \
74				$'Diff:\n'"$outdiff"
75		fi
76
77	elif [[ -f "$basename.err" ]] && [[ $expectexit -ne 0 ]]; then
78		if ! outdiff=$(diff "$basename.err" "$tmperr"); then
79			outputerror=$(<$tmperr)
80			rm $tmpout $tmperr $tmpin
81			log_fail $'Error mismatch. Expected:\n' \
82				"$(<$basename.err)"$'\nBut got:\n'"$outputerror"$'\n' \
83				$'Diff:\n'"$outdiff"
84		fi
85
86	elif [[ -n $expecterror ]] && [[ $expectexit -ne 0 ]]; then
87		if ! grep -q "$expecterror" $tmperr; then
88			outputerror=$(<$tmperr)
89			rm $tmpout $tmperr $tmpin
90			log_fail $'Error mismatch. Expected to contain:\n' \
91				"$expecterror"$'\nBut got:\n'"$outputerror"$'\n'
92		fi
93
94	elif [[ $expectexit -ne 0 ]]; then
95		#
96		# If there's no expected output, error reporting is allowed to
97		# vary, but ensure that we didn't fail silently.
98		#
99		if [[ -z "$(<$tmperr)" ]]; then
100			rm $tmpout $tmperr $tmpin
101			log_fail "error with no stderr output"
102		fi
103	fi
104
105	#
106	# Clean up all temp files except $tmpin which is
107	# reused for the second invocation of log_program.
108	#
109	rm $tmpout $tmperr
110}
111
112#
113# Even though the command's arguments are passed correctly
114# to the log_must_program family of wrappers the majority
115# of the time, zcp scripts passed as HERE documents can
116# make things trickier (see comment within the function
117# below) in the ordering of the commands arguments and how
118# they are passed. Thus, with this function we reconstruct
119# them to ensure that they are passed properly.
120#
121function log_program_construct_args
122{
123	typeset tmpin=$1
124	shift
125
126	args=""
127	i=0
128	while getopts "nt:m:" opt; do
129		case $opt in
130			t) args="$args -t $OPTARG"; i=$(($i + 2)) ;;
131			m) args="$args -m $OPTARG"; i=$(($i + 2)) ;;
132			n) args="$args -n"; i=$(($i + 1)) ;;
133		esac
134	done
135	shift $i
136
137	pool=$1
138	shift
139
140	infile=$1
141	shift
142
143	#
144	# Copy the contents of the original channel program to $tmpin.
145	#
146	# If $infile currently holds "-" (a dash) it means that we consume a
147	# HERE doc from stdin, otherwise $infile is a file path.
148	#
149	cat $infile > $tmpin
150
151	lua_args=$@
152
153	echo "$args $pool $tmpin $lua_args"
154}
155
156#
157# Program should complete successfully
158# when run in either context.
159#
160function log_must_program
161{
162	typeset tmpin=$(mktemp)
163
164	program_args=$(log_program_construct_args $tmpin $@)
165
166	log_program 0 "" $tmpin "-n $program_args"
167	log_program 0 "" $tmpin "$program_args"
168
169	rm $tmpin
170}
171#
172# Program should error as expected in
173# the same way in both contexts.
174#
175function log_mustnot_checkerror_program
176{
177	typeset expecterror=$1
178	shift
179	typeset tmpin=$(mktemp)
180
181	program_args=$(log_program_construct_args $tmpin $@)
182
183	log_program 1 "$expecterror" $tmpin "-n $program_args"
184	log_program 1 "$expecterror" $tmpin "$program_args"
185
186	rm $tmpin
187}
188
189#
190# Program should fail when run in either
191# context.
192#
193function log_mustnot_program
194{
195	log_mustnot_checkerror_program "" $@
196}
197
198
199#
200# Program should error as expected in
201# open context but complete successfully
202# in syncing context.
203#
204function log_mustnot_checkerror_program_open
205{
206	typeset expecterror=$1
207	shift
208	typeset tmpin=$(mktemp)
209
210	program_args=$(log_program_construct_args $tmpin $@)
211
212	log_program 1 "$expecterror" $tmpin "-n $program_args"
213	log_program 0 "" $tmpin "$program_args"
214
215	rm $tmpin
216}
217
218#
219# Program should complete successfully
220# when run in syncing context but fail
221# when attempted to run in open context.
222#
223function log_must_program_sync
224{
225	log_mustnot_checkerror_program_open "requires passing sync=TRUE" $@
226}
227