]> granicus.if.org Git - zfs/blob - tests/zfs-tests/tests/functional/channel_program/channel_common.kshlib
OpenZFS 8677 - Open-Context Channel Programs
[zfs] / tests / zfs-tests / tests / functional / channel_program / channel_common.kshlib
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 (c) 2016, 2017 by Delphix. All rights reserved.
15 #
16
17 . $STF_SUITE/include/libtest.shlib
18
19 ZCP_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
30 function 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$(cat $tmpin)"
52         log_note "output:\n$(cat $tmpout)"
53         log_note "error:\n$(cat $tmperr)"
54
55         #
56         # Verify correct return value
57         #
58         if [[ $ret -ne $expectexit ]]; then
59                 rm $tmpout $tmperr $tmpin
60                 log_fail "return mismatch: expected $expectexit, got $ret"
61         fi
62
63         #
64         # Check the output or reported error for successful or error returns,
65         # respectively.
66         #
67         if [[ -f "$basename.out" ]] && [[ $expectexit -eq 0 ]]; then
68
69                 outdiff=$(diff "$basename.out" "$tmpout")
70                 if [[ $? -ne 0 ]]; then
71                         output=$(cat $tmpout)
72                         rm $tmpout $tmperr $tmpin
73                         log_fail "Output mismatch. Expected:\n" \
74                                 "$(cat $basename.out)\nBut got:\n$output\n" \
75                                 "Diff:\n$outdiff"
76                 fi
77
78         elif [[ -f "$basename.err" ]] && [[ $expectexit -ne 0 ]]; then
79
80                 outdiff=$(diff "$basename.err" "$tmperr")
81                 if [[ $? -ne 0 ]]; then
82                         outputerror=$(cat $tmperr)
83                         rm $tmpout $tmperr $tmpin
84                         log_fail "Error mismatch. Expected:\n" \
85                                 "$(cat $basename.err)\nBut got:\n$outputerror\n" \
86                                 "Diff:\n$outdiff"
87                 fi
88
89         elif [[ -n $expecterror ]] && [[ $expectexit -ne 0 ]]; then
90
91                 grep -q "$expecterror" $tmperr
92                 if [[ $? -ne 0 ]]; then
93                         outputerror=$(cat $tmperr)
94                         rm $tmpout $tmperr $tmpin
95                         log_fail "Error mismatch. Expected to contain:\n" \
96                                 "$expecterror\nBut got:\n$outputerror\n"
97                 fi
98
99         elif [[ $expectexit -ne 0 ]]; then
100                 #
101                 # If there's no expected output, error reporting is allowed to
102                 # vary, but ensure that we didn't fail silently.
103                 #
104                 if [[ -z "$(cat $tmperr)" ]]; then
105                         rm $tmpout $tmperr $tmpin
106                         log_fail "error with no stderr output"
107                 fi
108         fi
109
110         #
111         # Clean up all temp files except $tmpin which is
112         # reused for the second invocation of log_program.
113         #
114         rm $tmpout $tmperr
115 }
116
117 #
118 # Even though the command's arguments are passed correctly
119 # to the log_must_program family of wrappers the majority
120 # of the time, zcp scripts passed as HERE documents can
121 # make things trickier (see comment within the function
122 # below) in the ordering of the commands arguments and how
123 # they are passed. Thus, with this function we reconstruct
124 # them to ensure that they are passed properly.
125 #
126 function log_program_construct_args
127 {
128         typeset tmpin=$1
129         shift
130
131         args=""
132         i=0
133         while getopts "nt:m:" opt; do
134                 case $opt in
135                         t) args="$args -t $OPTARG"; i=$(($i + 2)) ;;
136                         m) args="$args -m $OPTARG"; i=$(($i + 2)) ;;
137                         n) args="$args -n"; i=$(($i + 1)) ;;
138                 esac
139         done
140         shift $i
141
142         pool=$1
143         shift
144
145         #
146         # Catch HERE document if it exists and save it within our
147         # temp file. The reason we do this is that since the
148         # log_must_program wrapper calls zfs-program twice (once
149         # for open context and once for syncing) the HERE doc
150         # is consumed in the first invocation and the second one
151         # does not have a program to run.
152         #
153         test -s /dev/stdin && cat > $tmpin
154
155         #
156         # If $tmpin has contents it means that we consumed a HERE
157         # doc and $1 currently holds "-" (a dash). If there is no
158         # HERE doc and $tmpin is empty, then we copy the contents
159         # of the original channel program to $tmpin.
160         #
161         [[ -s $tmpin ]] || cp $1 $tmpin
162         shift
163
164         lua_args=$@
165
166         echo "$args $pool $tmpin $lua_args"
167 }
168
169 #
170 # Program should complete successfully
171 # when run in either context.
172 #
173 function log_must_program
174 {
175         typeset tmpin=$(mktemp)
176
177         program_args=$(log_program_construct_args $tmpin $@)
178
179         log_program 0 "" $tmpin "-n $program_args"
180         log_program 0 "" $tmpin "$program_args"
181
182         rm $tmpin
183 }
184 #
185 # Program should error as expected in
186 # the same way in both contexts.
187 #
188 function log_mustnot_checkerror_program
189 {
190         typeset expecterror=$1
191         shift
192         typeset tmpin=$(mktemp)
193
194         program_args=$(log_program_construct_args $tmpin $@)
195
196         log_program 1 "$expecterror" $tmpin "-n $program_args"
197         log_program 1 "$expecterror" $tmpin "$program_args"
198
199         rm $tmpin
200 }
201
202 #
203 # Program should fail when run in either
204 # context.
205 #
206 function log_mustnot_program
207 {
208         log_mustnot_checkerror_program "" $@
209 }
210
211
212 #
213 # Program should error as expected in
214 # open context but complete successfully
215 # in syncing context.
216 #
217 function log_mustnot_checkerror_program_open
218 {
219         typeset expecterror=$1
220         shift
221         typeset tmpin=$(mktemp)
222
223         program_args=$(log_program_construct_args $tmpin $@)
224
225         log_program 1 "$expecterror" $tmpin "-n $program_args"
226         log_program 0 "" $tmpin "$program_args"
227
228         rm $tmpin
229 }
230
231 #
232 # Program should complete successfully
233 # when run in syncing context but fail
234 # when attempted to run in open context.
235 #
236 function log_must_program_sync
237 {
238         log_mustnot_checkerror_program_open "requires passing sync=TRUE" $@
239 }