xref: /freebsd/contrib/atf/atf-sh/atf-sh.3 (revision df21a004be237a1dccd03c7b47254625eea62fa9)
1.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
2.\" All rights reserved.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions and the following disclaimer.
9.\" 2. Redistributions in binary form must reproduce the above copyright
10.\"    notice, this list of conditions and the following disclaimer in the
11.\"    documentation and/or other materials provided with the distribution.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25.Dd May 11, 2025
26.Dt ATF-SH 3
27.Os
28.Sh NAME
29.Nm atf_add_test_case ,
30.Nm atf_check ,
31.Nm atf_check_equal ,
32.Nm atf_check_not_equal ,
33.Nm atf_config_get ,
34.Nm atf_config_has ,
35.Nm atf_expect_death ,
36.Nm atf_expect_exit ,
37.Nm atf_expect_fail ,
38.Nm atf_expect_pass ,
39.Nm atf_expect_signal ,
40.Nm atf_expect_timeout ,
41.Nm atf_fail ,
42.Nm atf_get ,
43.Nm atf_get_srcdir ,
44.Nm atf_init_test_cases ,
45.Nm atf_pass ,
46.Nm atf_require_kmod ,
47.Nm atf_require_prog ,
48.Nm atf_set ,
49.Nm atf_skip ,
50.Nm atf_test_case
51.Nd POSIX shell API to write ATF-based test programs
52.Sh SYNOPSIS
53.Nm atf_add_test_case
54.Qq name
55.Nm atf_check
56.Qq command
57.Nm atf_check_equal
58.Qq expected_expression
59.Qq actual_expression
60.Nm atf_check_not_equal
61.Qq expected_expression
62.Qq actual_expression
63.Nm atf_config_get
64.Qq var_name
65.Nm atf_config_has
66.Qq var_name
67.Nm atf_expect_death
68.Qq reason
69.Qq ...
70.Nm atf_expect_exit
71.Qq exitcode
72.Qq reason
73.Qq ...
74.Nm atf_expect_fail
75.Qq reason
76.Qq ...
77.Nm atf_expect_pass
78.Qq
79.Nm atf_expect_signal
80.Qq signo
81.Qq reason
82.Qq ...
83.Nm atf_expect_timeout
84.Qq reason
85.Qq ...
86.Nm atf_fail
87.Qq reason
88.Nm atf_get
89.Qq var_name
90.Nm atf_get_srcdir
91.Nm atf_init_test_cases
92.Qq name
93.Nm atf_pass
94.Nm atf_require_kmod
95.Qq kmod_name
96.Nm atf_require_prog
97.Qq prog_name
98.Nm atf_set
99.Qq var_name
100.Qq value
101.Nm atf_skip
102.Qq reason
103.Nm atf_test_case
104.Qq name
105.Qq cleanup
106.Sh DESCRIPTION
107ATF
108provides a simple but powerful interface to easily write test programs in
109the POSIX shell language.
110These are extremely helpful given that they are trivial to write due to the
111language simplicity and the great deal of available external tools, so they
112are often ideal to test other applications at the user level.
113.Pp
114Test programs written using this library must be run using the
115.Xr atf-sh 1
116interpreter by putting the following on their very first line:
117.Bd -literal -offset indent
118#! /usr/bin/env atf-sh
119.Ed
120.Pp
121Shell-based test programs always follow this template:
122.Bd -literal -offset indent
123atf_test_case tc1
124tc1_head() {
125    ... first test case's header ...
126}
127tc1_body() {
128    ... first test case's body ...
129}
130
131atf_test_case tc2 cleanup
132tc2_head() {
133    ... second test case's header ...
134}
135tc2_body() {
136    ... second test case's body ...
137}
138tc2_cleanup() {
139    ... second test case's cleanup ...
140}
141
142\&... additional test cases ...
143
144atf_init_test_cases() {
145    atf_add_test_case tc1
146    atf_add_test_case tc2
147    ... add additional test cases ...
148}
149.Ed
150.Ss Definition of test cases
151Test cases have an identifier and are composed of three different parts:
152the header, the body and an optional cleanup routine, all of which are
153described in
154.Xr atf-test-case 4 .
155To define test cases, one can use the
156.Nm atf_test_case
157function, which takes a first parameter specifying the test case's
158name and instructs the library to set things up to accept it as a valid
159test case.
160The second parameter is optional and, if provided, must be
161.Sq cleanup ;
162providing this parameter allows defining a cleanup routine for the test
163case.
164It is important to note that this function
165.Em does not
166set the test case up for execution when the program is run.
167In order to do so, a later registration is needed through the
168.Nm atf_add_test_case
169function detailed in
170.Sx Program initialization .
171.Pp
172Later on, one must define the three parts of the body by providing two
173or three functions (remember that the cleanup routine is optional).
174These functions are named after the test case's identifier, and are
175.Nm \*(Ltid\*(Gt_head ,
176.Nm \*(Ltid\*(Gt_body
177and
178.Nm \*(Ltid\*(Gt_cleanup .
179None of these take parameters when executed.
180.Ss Program initialization
181The test program must define an
182.Nm atf_init_test_cases
183function, which is in charge of registering the test cases that will be
184executed at run time by using the
185.Nm atf_add_test_case
186function, which takes the name of a test case as its single parameter.
187This main function should not do anything else, except maybe sourcing
188auxiliary source files that define extra variables and functions.
189.Ss Configuration variables
190The test case has read-only access to the current configuration variables
191through the
192.Nm atf_config_has
193and
194.Nm atf_config_get
195methods.
196The former takes a single parameter specifying a variable name and returns
197a boolean indicating whether the variable is defined or not.
198The latter can take one or two parameters.
199If it takes only one, it specifies the variable from which to get the
200value, and this variable must be defined.
201If it takes two, the second one specifies a default value to be returned
202if the variable is not available.
203.Ss Access to the source directory
204It is possible to get the path to the test case's source directory from
205anywhere in the test program by using the
206.Nm atf_get_srcdir
207function.
208It is interesting to note that this can be used inside
209.Nm atf_init_test_cases
210to silently include additional helper files from the source directory.
211.Ss Requiring kernel modules
212Aside from the
213.Va require.kmods
214meta-data variable available in the header only, one can also check for
215additional kernel modules in the test case's body by using the
216.Nm atf_require_kmod
217function, which takes the name of a single kernel module.
218If it is not found, the test case will be automatically skipped.
219.Ss Requiring programs
220Aside from the
221.Va require.progs
222meta-data variable available in the header only, one can also check for
223additional programs in the test case's body by using the
224.Nm atf_require_prog
225function, which takes the base name or full path of a single binary.
226Relative paths are forbidden.
227If it is not found, the test case will be automatically skipped.
228.Ss Test case finalization
229The test case finalizes either when the body reaches its end, at which
230point the test is assumed to have
231.Em passed ,
232or at any explicit call to
233.Nm atf_pass ,
234.Nm atf_fail
235or
236.Nm atf_skip .
237These three functions terminate the execution of the test case immediately.
238The cleanup routine will be processed afterwards in a completely automated
239way, regardless of the test case's termination reason.
240.Pp
241.Nm atf_pass
242does not take any parameters.
243.Nm atf_fail
244and
245.Nm atf_skip
246take a single string parameter that describes why the test case failed or
247was skipped, respectively.
248It is very important to provide a clear error message in both cases so that
249the user can quickly know why the test did not pass.
250.Ss Expectations
251Everything explained in the previous section changes when the test case
252expectations are redefined by the programmer.
253.Pp
254Each test case has an internal state called
255.Sq expect
256that describes what the test case expectations are at any point in time.
257The value of this property can change during execution by any of:
258.Bl -tag -width indent
259.It Nm atf_expect_death Qo reason Qc Qo ... Qc
260Expects the test case to exit prematurely regardless of the nature of the
261exit.
262.It Nm atf_expect_exit Qo exitcode Qc Qo reason Qc Qo ... Qc
263Expects the test case to exit cleanly.
264If
265.Va exitcode
266is not
267.Sq -1 ,
268the runtime engine will validate that the exit code of the test case
269matches the one provided in this call.
270Otherwise, the exact value will be ignored.
271.It Nm atf_expect_fail Qo reason Qc
272Any failure raised in this mode is recorded, but such failures do not report
273the test case as failed; instead, the test case finalizes cleanly and is
274reported as
275.Sq expected failure ;
276this report includes the provided
277.Fa reason
278as part of it.
279If no error is raised while running in this mode, then the test case is
280reported as
281.Sq failed .
282.Pp
283This mode is useful to reproduce actual known bugs in tests.
284Whenever the developer fixes the bug later on, the test case will start
285reporting a failure, signaling the developer that the test case must be
286adjusted to the new conditions.
287In this situation, it is useful, for example, to set
288.Fa reason
289as the bug number for tracking purposes.
290.It Nm atf_expect_pass
291This is the normal mode of execution.
292In this mode, any failure is reported as such to the user and the test case
293is marked as
294.Sq failed .
295.It Nm atf_expect_signal Qo signo Qc Qo reason Qc Qo ... Qc
296Expects the test case to terminate due to the reception of a signal.
297If
298.Va signo
299is not
300.Sq -1 ,
301the runtime engine will validate that the signal that terminated the test
302case matches the one provided in this call.
303Otherwise, the exact value will be ignored.
304.It Nm atf_expect_timeout Qo reason Qc Qo ... Qc
305Expects the test case to execute for longer than its timeout.
306.El
307.Ss Helper functions for common checks
308.Bl -tag -width indent
309.It Nm atf_check Qo [options] Qc Qo command Qc Qo [args] Qc
310Executes a command, performs checks on its exit code and its output, and
311fails the test case if any of the checks is not successful.
312This function is particularly useful in integration tests that verify the
313correct functioning of a binary.
314.Pp
315Internally, this function is just a wrapper over the
316.Xr atf-check 1
317tool (whose manual page provides all details on the calling syntax).
318You should always use the
319.Nm atf_check
320function instead of the
321.Xr atf-check 1
322tool in your scripts; the latter is not even in the path.
323.It Nm atf_check_equal Qo expected_expression Qc Qo actual_expression Qc
324This function takes two expressions, evaluates them and, if their
325results differ, aborts the test case with an appropriate failure message.
326The common style is to put the expected value in the first parameter and the
327actual value in the second parameter.
328.It Nm atf_check_not_equal Qo expected_expression Qc Qo actual_expression Qc
329This function takes two expressions, evaluates them and, if their
330results are equal, aborts the test case with an appropriate failure message.
331The common style is to put the expected value in the first parameter and the
332actual value in the second parameter.
333.El
334.Sh EXAMPLES
335The following shows a complete test program with a single test case that
336validates the addition operator:
337.Bd -literal -offset indent
338atf_test_case addition
339addition_head() {
340    atf_set "descr" "Sample tests for the addition operator"
341}
342addition_body() {
343    atf_check_equal 0 $((0 + 0))
344    atf_check_equal 1 $((0 + 1))
345    atf_check_equal 1 $((1 + 0))
346
347    atf_check_equal 2 $((1 + 1))
348
349    atf_check_equal 300 $((100 + 200))
350}
351
352atf_init_test_cases() {
353    atf_add_test_case addition
354}
355.Ed
356.Pp
357This other example shows how to include a file with extra helper functions
358in the test program:
359.Bd -literal -offset indent
360\&... definition of test cases ...
361
362atf_init_test_cases() {
363    . $(atf_get_srcdir)/helper_functions.sh
364
365    atf_add_test_case foo1
366    atf_add_test_case foo2
367}
368.Ed
369.Pp
370This example demonstrates the use of the very useful
371.Nm atf_check
372function:
373.Bd -literal -offset indent
374# Check for silent output
375atf_check -s exit:0 -o empty -e empty true
376
377# Check for silent output and failure
378atf_check -s exit:1 -o empty -e empty false
379
380# Check for known stdout and silent stderr
381echo foo >expout
382atf_check -s exit:0 -o file:expout -e empty echo foo
383
384# Generate a file for later inspection
385atf_check -s exit:0 -o save:stdout -e empty ls
386grep foo ls || atf_fail "foo file not found in listing"
387
388# Or just do the match along the way
389atf_check -s exit:0 -o match:"^foo$" -e empty ls
390.Ed
391.Sh SEE ALSO
392.Xr atf-check 1 ,
393.Xr atf-sh 1 ,
394.Xr atf-test-program 1 ,
395.Xr atf-test-case 4
396