1e2207522Sjmmv.\" 2e2207522Sjmmv.\" Automated Testing Framework (atf) 3e2207522Sjmmv.\" 4a551a20fSjmmv.\" Copyright (c) 2008 The NetBSD Foundation, Inc. 5e2207522Sjmmv.\" All rights reserved. 6e2207522Sjmmv.\" 7e2207522Sjmmv.\" Redistribution and use in source and binary forms, with or without 8e2207522Sjmmv.\" modification, are permitted provided that the following conditions 9e2207522Sjmmv.\" are met: 10e2207522Sjmmv.\" 1. Redistributions of source code must retain the above copyright 11e2207522Sjmmv.\" notice, this list of conditions and the following disclaimer. 12e2207522Sjmmv.\" 2. Redistributions in binary form must reproduce the above copyright 13e2207522Sjmmv.\" notice, this list of conditions and the following disclaimer in the 14e2207522Sjmmv.\" documentation and/or other materials provided with the distribution. 15e2207522Sjmmv.\" 16e2207522Sjmmv.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17e2207522Sjmmv.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18e2207522Sjmmv.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19e2207522Sjmmv.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20e2207522Sjmmv.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21e2207522Sjmmv.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22e2207522Sjmmv.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23e2207522Sjmmv.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24e2207522Sjmmv.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25e2207522Sjmmv.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26e2207522Sjmmv.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27e2207522Sjmmv.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28e2207522Sjmmv.\" 29*7f0357d3Skre.Dd May 15, 2017 30e2207522Sjmmv.Dt ATF-SH-API 3 31e2207522Sjmmv.Os 32e2207522Sjmmv.Sh NAME 33e2207522Sjmmv.Nm atf_add_test_case , 34e2207522Sjmmv.Nm atf_check , 35e2207522Sjmmv.Nm atf_check_equal , 36e2207522Sjmmv.Nm atf_config_get , 37e2207522Sjmmv.Nm atf_config_has , 38edebbb8eSjmmv.Nm atf_expect_death , 39edebbb8eSjmmv.Nm atf_expect_exit , 40edebbb8eSjmmv.Nm atf_expect_fail , 41edebbb8eSjmmv.Nm atf_expect_pass , 42edebbb8eSjmmv.Nm atf_expect_signal , 43edebbb8eSjmmv.Nm atf_expect_timeout , 44e2207522Sjmmv.Nm atf_fail , 45e2207522Sjmmv.Nm atf_get , 46e2207522Sjmmv.Nm atf_get_srcdir , 47e2207522Sjmmv.Nm atf_pass , 48e2207522Sjmmv.Nm atf_require_prog , 49e2207522Sjmmv.Nm atf_set , 50edebbb8eSjmmv.Nm atf_skip , 51895f502bSjmmv.Nm atf_test_case 52e2207522Sjmmv.Nd POSIX shell API to write ATF-based test programs 53e2207522Sjmmv.Sh SYNOPSIS 54*7f0357d3Skre.Ic atf_add_test_case Dq name 55*7f0357d3Skre.br 56*7f0357d3Skre.Ic atf_check Dq command 57*7f0357d3Skre.br 58*7f0357d3Skre.Ic atf_check_equal Do expr1 Dc Dq expr2 59*7f0357d3Skre.br 60*7f0357d3Skre.Ic atf_config_get Dq var_name 61*7f0357d3Skre.br 62*7f0357d3Skre.Ic atf_config_has Dq var_name 63*7f0357d3Skre.br 64*7f0357d3Skre.Ic atf_expect_death Do reason Dc Dq \&... 65*7f0357d3Skre.br 66*7f0357d3Skre.Ic atf_expect_exit Do exitcode Dc Do reason Dc Dq \&... 67*7f0357d3Skre.br 68*7f0357d3Skre.Ic atf_expect_fail Do reason Dc Dq \&... 69*7f0357d3Skre.br 70*7f0357d3Skre.Ic atf_expect_pass 71*7f0357d3Skre.br 72*7f0357d3Skre.Ic atf_expect_signal Do signo Dc Do reason Dc Dq \&... 73*7f0357d3Skre.br 74*7f0357d3Skre.Ic atf_expect_timeout Do reason Dc Dq \&... 75*7f0357d3Skre.br 76*7f0357d3Skre.Ic atf_fail Dq reason 77*7f0357d3Skre.br 78*7f0357d3Skre.Ic atf_get Dq var_name 79*7f0357d3Skre.br 80*7f0357d3Skre.Ic atf_get_srcdir 81*7f0357d3Skre.br 82*7f0357d3Skre.Ic atf_pass 83*7f0357d3Skre.br 84*7f0357d3Skre.Ic atf_require_prog Dq prog_name 85*7f0357d3Skre.br 86*7f0357d3Skre.Ic atf_set Do var_name Dc Dq value 87*7f0357d3Skre.br 88*7f0357d3Skre.Ic atf_skip Dq reason 89*7f0357d3Skre.br 90*7f0357d3Skre.Ic atf_test_case Do name Dc Dq cleanup 91*7f0357d3Skre.br 92e2207522Sjmmv.Sh DESCRIPTION 93e2207522SjmmvATF 94e2207522Sjmmvprovides a simple but powerful interface to easily write test programs in 95e2207522Sjmmvthe POSIX shell language. 96e2207522SjmmvThese are extremely helpful given that they are trivial to write due to the 97e2207522Sjmmvlanguage simplicity and the great deal of available external tools, so they 98e2207522Sjmmvare often ideal to test other applications at the user level. 99e2207522Sjmmv.Pp 1009b3149ccSjmmvTest programs written using this library must be run using the 1019b3149ccSjmmv.Xr atf-sh 1 1029b3149ccSjmmvinterpreter by putting the following on their very first line: 1039b3149ccSjmmv.Bd -literal -offset indent 1049b3149ccSjmmv#! /usr/bin/env atf-sh 1059b3149ccSjmmv.Ed 106e2207522Sjmmv.Pp 107e2207522SjmmvShell-based test programs always follow this template: 108e2207522Sjmmv.Bd -literal -offset indent 109e2207522Sjmmvatf_test_case tc1 110e2207522Sjmmvtc1_head() { 111e2207522Sjmmv ... first test case's header ... 112e2207522Sjmmv} 113e2207522Sjmmvtc1_body() { 114e2207522Sjmmv ... first test case's body ... 115e2207522Sjmmv} 116e2207522Sjmmv 117edebbb8eSjmmvatf_test_case tc2 cleanup 118e2207522Sjmmvtc2_head() { 119e2207522Sjmmv ... second test case's header ... 120e2207522Sjmmv} 121e2207522Sjmmvtc2_body() { 122e2207522Sjmmv ... second test case's body ... 123e2207522Sjmmv} 124e2207522Sjmmvtc2_cleanup() { 125e2207522Sjmmv ... second test case's cleanup ... 126e2207522Sjmmv} 127e2207522Sjmmv 128e2207522Sjmmv.Ns ... additional test cases ... 129e2207522Sjmmv 130e2207522Sjmmvatf_init_test_cases() { 131e2207522Sjmmv atf_add_test_case tc1 132e2207522Sjmmv atf_add_test_case tc2 133e2207522Sjmmv ... add additional test cases ... 134e2207522Sjmmv} 135e2207522Sjmmv.Ed 136*7f0357d3Skre.Pp 137*7f0357d3SkreAll of these functions are required to return with an exit-status of 138*7f0357d3Skrezero, or ATF will determine that the test is faulty. 139*7f0357d3SkreIn particular, this means that none may end with a conditional like: 140*7f0357d3Skre.Bd -literal -offset indent 141*7f0357d3Skreatf_sh_function() { 142*7f0357d3Skre ... appropriate code here ... 143*7f0357d3Skre condition-test && { 144*7f0357d3Skre ... more code here ... 145*7f0357d3Skre } 146*7f0357d3Skre} 147*7f0357d3Skre.Ed 148*7f0357d3Skre.Pp 149*7f0357d3Skreas if condition-test fails 150*7f0357d3Skrethe return code from atf_sh_function will not be 0. 151*7f0357d3SkreThis can be corrected by adding 152*7f0357d3Skre.Bd -literal -offset indent 153*7f0357d3Skre return 0 154*7f0357d3Skre.Ed 155*7f0357d3Skre.Pp 156*7f0357d3Skrebefore the end of the function, or by writing it as 157*7f0357d3Skre.Bd -literal -offset indent 158*7f0357d3Skreatf_sh_function() { 159*7f0357d3Skre ... appropriate code here ... 160*7f0357d3Skre if condition-test 161*7f0357d3Skre then 162*7f0357d3Skre ... more code here ... 163*7f0357d3Skre fi 164*7f0357d3Skre} 165*7f0357d3Skre.Ed 166e2207522Sjmmv.Ss Definition of test cases 167e2207522SjmmvTest cases have an identifier and are composed of three different parts: 168e2207522Sjmmvthe header, the body and an optional cleanup routine, all of which are 169e2207522Sjmmvdescribed in 170edebbb8eSjmmv.Xr atf-test-case 4 . 171e2207522SjmmvTo define test cases, one can use the 172*7f0357d3Skre.Ic atf_test_case 173edebbb8eSjmmvfunction, which takes a first parameter specifiying the test case's 174e2207522Sjmmvname and instructs the library to set things up to accept it as a valid 175e2207522Sjmmvtest case. 176edebbb8eSjmmvThe second parameter is optional and, if provided, must be 177edebbb8eSjmmv.Sq cleanup ; 178edebbb8eSjmmvproviding this parameter allows defining a cleanup routine for the test 179edebbb8eSjmmvcase. 180edebbb8eSjmmvIt is important to note that this function 181e2207522Sjmmv.Em does not 182e2207522Sjmmvset the test case up for execution when the program is run. 183e2207522SjmmvIn order to do so, a later registration is needed through the 184*7f0357d3Skre.Ic atf_add_test_case 185e2207522Sjmmvfunction detailed in 186e2207522Sjmmv.Sx Program initialization . 187e2207522Sjmmv.Pp 188e2207522SjmmvLater on, one must define the three parts of the body by providing two 189e2207522Sjmmvor three functions (remember that the cleanup routine is optional). 190e2207522SjmmvThese functions are named after the test case's identifier, and are 191*7f0357d3Skre.Ic <id>_head , 192*7f0357d3Skre.Ic <id>_body 193e2207522Sjmmvand 194*7f0357d3Skre.Ic <id>_cleanup. 195e2207522SjmmvNone of these take parameters when executed. 196e2207522Sjmmv.Ss Program initialization 197e2207522SjmmvThe test program must define an 198*7f0357d3Skre.Ic atf_init_test_cases 199e2207522Sjmmvfunction, which is in charge of registering the test cases that will be 200e2207522Sjmmvexecuted at run time by using the 201*7f0357d3Skre.Ic atf_add_test_case 202e2207522Sjmmvfunction, which takes the name of a test case as its single parameter. 203e2207522SjmmvThis main function should not do anything else, except maybe sourcing 204*7f0357d3Skreauxiliary source files that define extra variables and functions, 205*7f0357d3Skreor perhaps running simple tests to determine which test cases to add. 206e2207522Sjmmv.Ss Configuration variables 207e2207522SjmmvThe test case has read-only access to the current configuration variables 208e2207522Sjmmvthrough the 209*7f0357d3Skre.Ic atf_config_has 210e2207522Sjmmvand 211*7f0357d3Skre.Ic atf_config_get 212e2207522Sjmmvmethods. 213e2207522SjmmvThe former takes a single parameter specifying a variable name and returns 214e2207522Sjmmva boolean indicating whether the variable is defined or not. 215e2207522SjmmvThe latter can take one or two parameters. 216e2207522SjmmvIf it takes only one, it specifies the variable from which to get the 217e2207522Sjmmvvalue, and this variable must be defined. 218e2207522SjmmvIf it takes two, the second one specifies a default value to be returned 219e2207522Sjmmvif the variable is not available. 220e2207522Sjmmv.Ss Access to the source directory 221e2207522SjmmvIt is possible to get the path to the test case's source directory from 222e2207522Sjmmvanywhere in the test program by using the 223*7f0357d3Skre.Ic atf_get_srcdir 224e2207522Sjmmvfunction. 225e2207522SjmmvIt is interesting to note that this can be used inside 226*7f0357d3Skre.Ic atf_init_test_cases 227e2207522Sjmmvto silently include additional helper files from the source directory. 228e2207522Sjmmv.Ss Requiring programs 229e2207522SjmmvAside from the 230e2207522Sjmmv.Va require.progs 231e2207522Sjmmvmeta-data variable available in the header only, one can also check for 232e2207522Sjmmvadditional programs in the test case's body by using the 233*7f0357d3Skre.Ic atf_require_prog 234e2207522Sjmmvfunction, which takes the base name or full path of a single binary. 235e2207522SjmmvRelative paths are forbidden. 236e2207522SjmmvIf it is not found, the test case will be automatically skipped. 237e2207522Sjmmv.Ss Test case finalization 238e2207522SjmmvThe test case finalizes either when the body reaches its end, at which 239e2207522Sjmmvpoint the test is assumed to have 240e2207522Sjmmv.Em passed , 241e2207522Sjmmvor at any explicit call to 242*7f0357d3Skre.Ic atf_pass , 243*7f0357d3Skre.Ic atf_fail 244*7f0357d3Skre.Ic atf_skip . 245e2207522SjmmvThese three functions terminate the execution of the test case immediately. 246e2207522SjmmvThe cleanup routine will be processed afterwards in a completely automated 247e2207522Sjmmvway, regardless of the test case's termination reason. 248e2207522Sjmmv.Pp 249e2207522Sjmmv.Fn atf_pass 250e2207522Sjmmvdoes not take any parameters. 251e2207522Sjmmv.Fn atf_fail 252e2207522Sjmmvand 253e2207522Sjmmv.Fn atf_skip 254e2207522Sjmmvtake a single string parameter that describes why the test case failed or 255e2207522Sjmmvwas skipped, respectively. 256e2207522SjmmvIt is very important to provide a clear error message in both cases so that 257e2207522Sjmmvthe user can quickly know why the test did not pass. 258*7f0357d3SkreThis message must be a single line (no embedded newline characers.) 259edebbb8eSjmmv.Ss Expectations 260edebbb8eSjmmvEverything explained in the previous section changes when the test case 261edebbb8eSjmmvexpectations are redefined by the programmer. 262edebbb8eSjmmv.Pp 263edebbb8eSjmmvEach test case has an internal state called 264edebbb8eSjmmv.Sq expect 265edebbb8eSjmmvthat describes what the test case expectations are at any point in time. 266edebbb8eSjmmvThe value of this property can change during execution by any of: 267edebbb8eSjmmv.Bl -tag -width indent 268*7f0357d3Skre.It Ic atf_expect_death Do reason Dc Dq \&... 269edebbb8eSjmmvExpects the test case to exit prematurely regardless of the nature of the 270edebbb8eSjmmvexit. 271*7f0357d3Skre.It Ic atf_expect_exit Do exitcode Dc Do reason Dc Dq \&... 272edebbb8eSjmmvExpects the test case to exit cleanly. 273edebbb8eSjmmvIf 274edebbb8eSjmmv.Va exitcode 275edebbb8eSjmmvis not 276*7f0357d3Skre.Sq \-1 , 277edebbb8eSjmmv.Xr atf-run 1 278edebbb8eSjmmvwill validate that the exit code of the test case matches the one provided 279edebbb8eSjmmvin this call. 280edebbb8eSjmmvOtherwise, the exact value will be ignored. 281*7f0357d3Skre.It Ic atf_expect_fail Dq reason 282edebbb8eSjmmvAny failure raised in this mode is recorded, but such failures do not report 283edebbb8eSjmmvthe test case as failed; instead, the test case finalizes cleanly and is 284edebbb8eSjmmvreported as 285edebbb8eSjmmv.Sq expected failure ; 286edebbb8eSjmmvthis report includes the provided 287edebbb8eSjmmv.Fa reason 288edebbb8eSjmmvas part of it. 289edebbb8eSjmmvIf no error is raised while running in this mode, then the test case is 290edebbb8eSjmmvreported as 291edebbb8eSjmmv.Sq failed . 292edebbb8eSjmmv.Pp 293edebbb8eSjmmvThis mode is useful to reproduce actual known bugs in tests. 294edebbb8eSjmmvWhenever the developer fixes the bug later on, the test case will start 295edebbb8eSjmmvreporting a failure, signaling the developer that the test case must be 296edebbb8eSjmmvadjusted to the new conditions. 297edebbb8eSjmmvIn this situation, it is useful, for example, to set 298*7f0357d3Skre.Va reason 299edebbb8eSjmmvas the bug number for tracking purposes. 300*7f0357d3Skre.It Ic atf_expect_pass 301edebbb8eSjmmvThis is the normal mode of execution. 302edebbb8eSjmmvIn this mode, any failure is reported as such to the user and the test case 303edebbb8eSjmmvis marked as 304edebbb8eSjmmv.Sq failed . 305*7f0357d3Skre.It Ic atf_expect_signal Do signo Dc Do reason Dc Dq \&... 306edebbb8eSjmmvExpects the test case to terminate due to the reception of a signal. 307edebbb8eSjmmvIf 308edebbb8eSjmmv.Va signo 309edebbb8eSjmmvis not 310*7f0357d3Skre.Sq \-1 , 311edebbb8eSjmmv.Xr atf-run 1 312edebbb8eSjmmvwill validate that the signal that terminated the test case matches the one 313edebbb8eSjmmvprovided in this call. 314edebbb8eSjmmvOtherwise, the exact value will be ignored. 315*7f0357d3Skre.It Ic atf_expect_timeout Do reason Dc Dq \&... 316edebbb8eSjmmvExpects the test case to execute for longer than its timeout. 317edebbb8eSjmmv.El 318e2207522Sjmmv.Ss Helper functions for common checks 319*7f0357d3Skre.Ic atf_check Oo options Oc command Op args 320e2207522Sjmmv.Pp 32112aa0b5aSjmmvThis function wraps the execution of the 32212aa0b5aSjmmv.Nm atf-check 32312aa0b5aSjmmvtool and makes the test case fail if the tool reports failure. 32412aa0b5aSjmmvYou should always use this function instead of the tool in your scripts. 32512aa0b5aSjmmvFor more details on the parameters of this function, refer to 32612aa0b5aSjmmv.Xr atf-check 1 . 327e2207522Sjmmv.Pp 328*7f0357d3Skre.Ic atf_check_equal expr1 expr2 329e2207522Sjmmv.Pp 330e2207522SjmmvThis function takes two expressions, evaluates them and, if their 331e2207522Sjmmvresults differ, aborts the test case with an appropriate failure message. 332e2207522Sjmmv.Sh EXAMPLES 333e2207522SjmmvThe following shows a complete test program with a single test case that 334e2207522Sjmmvvalidates the addition operator: 335e2207522Sjmmv.Bd -literal -offset indent 336e2207522Sjmmvatf_test_case addition 337e2207522Sjmmvaddition_head() { 338e2207522Sjmmv atf_set "descr" "Sample tests for the addition operator" 339e2207522Sjmmv} 340e2207522Sjmmvaddition_body() { 341e2207522Sjmmv atf_check_equal $((0 + 0)) 0 342e2207522Sjmmv atf_check_equal $((0 + 1)) 1 343e2207522Sjmmv atf_check_equal $((1 + 0)) 0 344e2207522Sjmmv 345e2207522Sjmmv atf_check_equal $((1 + 1)) 2 346e2207522Sjmmv 347e2207522Sjmmv atf_check_equal $((100 + 200)) 300 348e2207522Sjmmv} 349e2207522Sjmmv 350e2207522Sjmmvatf_init_test_cases() { 351e2207522Sjmmv atf_add_test_case addition 352e2207522Sjmmv} 353e2207522Sjmmv.Ed 354e2207522Sjmmv.Pp 355e2207522SjmmvThis other example shows how to include a file with extra helper functions 356e2207522Sjmmvin the test program: 357e2207522Sjmmv.Bd -literal -offset indent 358e2207522Sjmmv.Ns ... definition of test cases ... 359e2207522Sjmmv 360e2207522Sjmmvatf_init_test_cases() { 361e2207522Sjmmv . $(atf_get_srcdir)/helper_functions.sh 362e2207522Sjmmv 363e2207522Sjmmv atf_add_test_case foo1 364e2207522Sjmmv atf_add_test_case foo2 365e2207522Sjmmv} 366e2207522Sjmmv.Ed 367e2207522Sjmmv.Pp 368e2207522SjmmvThis example demonstrates the use of the very useful 369e2207522Sjmmv.Fn atf_check 370e2207522Sjmmvfunction: 371e2207522Sjmmv.Bd -literal -offset indent 372e2207522Sjmmv# Check for silent output 373d780102eSjmmvatf_check -s exit:0 -o empty -e empty 'true' 374e2207522Sjmmv 375e2207522Sjmmv# Check for silent output and failure 376d780102eSjmmvatf_check -s exit:1 -o empty -e empty 'false' 377e2207522Sjmmv 378e2207522Sjmmv# Check for known stdout and silent stderr 379e2207522Sjmmvecho foo >expout 380d780102eSjmmvatf_check -s exit:0 -o file:expout -e empty 'echo foo' 381e2207522Sjmmv 382e2207522Sjmmv# Generate a file for later inspection 383d780102eSjmmvatf_check -s exit:0 -o save:stdout -e empty 'ls' 384e2207522Sjmmvgrep foo ls || atf_fail "foo file not found in listing" 385d780102eSjmmv 386d780102eSjmmv# Or just do the match along the way 387d780102eSjmmvatf_check -s exit:0 -o match:"^foo$" -e empty 'ls' 388e2207522Sjmmv.Ed 389e2207522Sjmmv.Sh SEE ALSO 3909b3149ccSjmmv.Xr atf-sh 1 , 391e2207522Sjmmv.Xr atf-test-program 1 , 392edebbb8eSjmmv.Xr atf-test-case 4 , 393edebbb8eSjmmv.Xr atf 7 394