1 1.1 jmmv # 2 1.1 jmmv # Automated Testing Framework (atf) 3 1.1 jmmv # 4 1.2 christos # Copyright (c) 2007 The NetBSD Foundation, Inc. 5 1.1 jmmv # All rights reserved. 6 1.1 jmmv # 7 1.1 jmmv # Redistribution and use in source and binary forms, with or without 8 1.1 jmmv # modification, are permitted provided that the following conditions 9 1.1 jmmv # are met: 10 1.1 jmmv # 1. Redistributions of source code must retain the above copyright 11 1.1 jmmv # notice, this list of conditions and the following disclaimer. 12 1.1 jmmv # 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmmv # notice, this list of conditions and the following disclaimer in the 14 1.1 jmmv # documentation and/or other materials provided with the distribution. 15 1.1 jmmv # 16 1.1 jmmv # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 1.1 jmmv # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 1.1 jmmv # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 1.1 jmmv # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 jmmv # IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 1.1 jmmv # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jmmv # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 1.1 jmmv # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 jmmv # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 1.1 jmmv # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 1.1 jmmv # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 1.1 jmmv # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 jmmv # 29 1.1 jmmv 30 1.2 christos set -e 31 1.2 christos 32 1.1 jmmv # ------------------------------------------------------------------------ 33 1.1 jmmv # GLOBAL VARIABLES 34 1.1 jmmv # ------------------------------------------------------------------------ 35 1.1 jmmv 36 1.2 christos # Values for the expect property. 37 1.2 christos Expect=pass 38 1.2 christos Expect_Reason= 39 1.1 jmmv 40 1.1 jmmv # A boolean variable that indicates whether we are parsing a test case's 41 1.1 jmmv # head or not. 42 1.1 jmmv Parsing_Head=false 43 1.1 jmmv 44 1.1 jmmv # The program name. 45 1.1 jmmv Prog_Name=${0##*/} 46 1.1 jmmv 47 1.1 jmmv # The file to which the test case will print its result. 48 1.2 christos Results_File= 49 1.1 jmmv 50 1.1 jmmv # The test program's source directory: i.e. where its auxiliary data files 51 1.1 jmmv # and helper utilities can be found. Can be overriden through the '-s' flag. 52 1.1 jmmv Source_Dir="$(dirname ${0})" 53 1.1 jmmv 54 1.1 jmmv # Indicates the test case we are currently processing. 55 1.1 jmmv Test_Case= 56 1.1 jmmv 57 1.1 jmmv # List of meta-data variables for the current test case. 58 1.1 jmmv Test_Case_Vars= 59 1.1 jmmv 60 1.1 jmmv # The list of all test cases provided by the test program. 61 1.1 jmmv Test_Cases= 62 1.1 jmmv 63 1.1 jmmv # ------------------------------------------------------------------------ 64 1.1 jmmv # PUBLIC INTERFACE 65 1.1 jmmv # ------------------------------------------------------------------------ 66 1.1 jmmv 67 1.1 jmmv # 68 1.1 jmmv # atf_add_test_case tc-name 69 1.1 jmmv # 70 1.1 jmmv # Adds the given test case to the list of test cases that form the test 71 1.1 jmmv # program. The name provided here must be accompanied by two functions 72 1.1 jmmv # named after it: <tc-name>_head and <tc-name>_body, and optionally by 73 1.1 jmmv # a <tc-name>_cleanup function. 74 1.1 jmmv # 75 1.1 jmmv atf_add_test_case() 76 1.1 jmmv { 77 1.1 jmmv Test_Cases="${Test_Cases} ${1}" 78 1.1 jmmv } 79 1.1 jmmv 80 1.1 jmmv # 81 1.1 jmmv # atf_check cmd expcode expout experr 82 1.1 jmmv # 83 1.1 jmmv # Executes atf-check with given arguments and automatically calls 84 1.1 jmmv # atf_fail in case of failure. 85 1.1 jmmv # 86 1.1 jmmv atf_check() 87 1.1 jmmv { 88 1.2 christos ${Atf_Check} "${@}" || \ 89 1.1 jmmv atf_fail "atf-check failed; see the output of the test for details" 90 1.1 jmmv } 91 1.1 jmmv 92 1.1 jmmv # 93 1.1 jmmv # atf_check_equal expr1 expr2 94 1.1 jmmv # 95 1.1 jmmv # Checks that expr1's value matches expr2's and, if not, raises an 96 1.1 jmmv # error. Ideally expr1 and expr2 should be provided quoted (not 97 1.1 jmmv # expanded) so that the error message is helpful; otherwise it will 98 1.1 jmmv # only show the values, not the expressions themselves. 99 1.1 jmmv # 100 1.1 jmmv atf_check_equal() 101 1.1 jmmv { 102 1.1 jmmv eval _val1=\"${1}\" 103 1.1 jmmv eval _val2=\"${2}\" 104 1.1 jmmv test "${_val1}" = "${_val2}" || \ 105 1.1 jmmv atf_fail "${1} != ${2} (${_val1} != ${_val2})" 106 1.1 jmmv } 107 1.1 jmmv 108 1.1 jmmv # 109 1.1 jmmv # atf_config_get varname [defvalue] 110 1.1 jmmv # 111 1.1 jmmv # Prints the value of a configuration variable. If it is not 112 1.1 jmmv # defined, prints the given default value. 113 1.1 jmmv # 114 1.1 jmmv atf_config_get() 115 1.1 jmmv { 116 1.1 jmmv _varname="__tc_config_var_$(_atf_normalize ${1})" 117 1.1 jmmv if [ ${#} -eq 1 ]; then 118 1.1 jmmv eval _value=\"\${${_varname}-__unset__}\" 119 1.1 jmmv [ "${_value}" = __unset__ ] && \ 120 1.1 jmmv _atf_error 1 "Could not find configuration variable \`${1}'" 121 1.1 jmmv echo ${_value} 122 1.1 jmmv elif [ ${#} -eq 2 ]; then 123 1.1 jmmv eval echo \${${_varname}-${2}} 124 1.1 jmmv else 125 1.1 jmmv _atf_error 1 "Incorrect number of parameters for atf_config_get" 126 1.1 jmmv fi 127 1.1 jmmv } 128 1.1 jmmv 129 1.1 jmmv # 130 1.1 jmmv # atf_config_has varname 131 1.1 jmmv # 132 1.1 jmmv # Returns a boolean indicating if the given configuration variable is 133 1.1 jmmv # defined or not. 134 1.1 jmmv # 135 1.1 jmmv atf_config_has() 136 1.1 jmmv { 137 1.1 jmmv _varname="__tc_config_var_$(_atf_normalize ${1})" 138 1.1 jmmv eval _value=\"\${${_varname}-__unset__}\" 139 1.1 jmmv [ "${_value}" != __unset__ ] 140 1.1 jmmv } 141 1.1 jmmv 142 1.1 jmmv # 143 1.2 christos # atf_expect_death reason 144 1.2 christos # 145 1.2 christos # Sets the expectations to 'death'. 146 1.2 christos # 147 1.2 christos atf_expect_death() 148 1.2 christos { 149 1.2 christos _atf_validate_expect 150 1.2 christos 151 1.2 christos Expect=death 152 1.2 christos _atf_create_resfile "expected_death: ${*}" 153 1.2 christos } 154 1.2 christos 155 1.2 christos # 156 1.2 christos # atf_expect_timeout reason 157 1.2 christos # 158 1.2 christos # Sets the expectations to 'timeout'. 159 1.2 christos # 160 1.2 christos atf_expect_timeout() 161 1.2 christos { 162 1.2 christos _atf_validate_expect 163 1.2 christos 164 1.2 christos Expect=timeout 165 1.2 christos _atf_create_resfile "expected_timeout: ${*}" 166 1.2 christos } 167 1.2 christos 168 1.2 christos # 169 1.2 christos # atf_expect_exit exitcode reason 170 1.2 christos # 171 1.2 christos # Sets the expectations to 'exit'. 172 1.2 christos # 173 1.2 christos atf_expect_exit() 174 1.2 christos { 175 1.2 christos _exitcode="${1}"; shift 176 1.2 christos 177 1.2 christos _atf_validate_expect 178 1.2 christos 179 1.2 christos Expect=exit 180 1.2 christos if [ "${_exitcode}" = "-1" ]; then 181 1.2 christos _atf_create_resfile "expected_exit: ${*}" 182 1.2 christos else 183 1.2 christos _atf_create_resfile "expected_exit(${_exitcode}): ${*}" 184 1.2 christos fi 185 1.2 christos } 186 1.2 christos 187 1.2 christos # 188 1.2 christos # atf_expect_fail reason 189 1.2 christos # 190 1.2 christos # Sets the expectations to 'fail'. 191 1.2 christos # 192 1.2 christos atf_expect_fail() 193 1.2 christos { 194 1.2 christos _atf_validate_expect 195 1.2 christos 196 1.2 christos Expect=fail 197 1.2 christos Expect_Reason="${*}" 198 1.2 christos } 199 1.2 christos 200 1.2 christos # 201 1.2 christos # atf_expect_pass 202 1.2 christos # 203 1.2 christos # Sets the expectations to 'pass'. 204 1.2 christos # 205 1.2 christos atf_expect_pass() 206 1.2 christos { 207 1.2 christos _atf_validate_expect 208 1.2 christos 209 1.2 christos Expect=pass 210 1.2 christos Expect_Reason= 211 1.2 christos } 212 1.2 christos 213 1.2 christos # 214 1.2 christos # atf_expect_signal signo reason 215 1.2 christos # 216 1.2 christos # Sets the expectations to 'signal'. 217 1.2 christos # 218 1.2 christos atf_expect_signal() 219 1.2 christos { 220 1.2 christos _signo="${1}"; shift 221 1.2 christos 222 1.2 christos _atf_validate_expect 223 1.2 christos 224 1.2 christos Expect=signal 225 1.2 christos if [ "${_signo}" = "-1" ]; then 226 1.2 christos _atf_create_resfile "expected_signal: ${*}" 227 1.2 christos else 228 1.2 christos _atf_create_resfile "expected_signal(${_signo}): ${*}" 229 1.2 christos fi 230 1.2 christos } 231 1.2 christos 232 1.2 christos # 233 1.2 christos # atf_expected_failure msg1 [.. msgN] 234 1.2 christos # 235 1.2 christos # Makes the test case report an expected failure with the given error 236 1.2 christos # message. Multiple words can be provided, which are concatenated with 237 1.2 christos # a single blank space. 238 1.2 christos # 239 1.2 christos atf_expected_failure() 240 1.2 christos { 241 1.2 christos _atf_create_resfile "expected_failure: ${Expect_Reason}: ${*}" 242 1.2 christos exit 0 243 1.2 christos } 244 1.2 christos 245 1.2 christos # 246 1.1 jmmv # atf_fail msg1 [.. msgN] 247 1.1 jmmv # 248 1.1 jmmv # Makes the test case fail with the given error message. Multiple 249 1.1 jmmv # words can be provided, in which case they are joined by a single 250 1.1 jmmv # blank space. 251 1.1 jmmv # 252 1.1 jmmv atf_fail() 253 1.1 jmmv { 254 1.2 christos case "${Expect}" in 255 1.2 christos fail) 256 1.2 christos atf_expected_failure "${@}" 257 1.2 christos ;; 258 1.2 christos pass) 259 1.2 christos _atf_create_resfile "failed: ${*}" 260 1.2 christos exit 1 261 1.2 christos ;; 262 1.2 christos *) 263 1.2 christos _atf_error 128 "Unreachable" 264 1.2 christos ;; 265 1.2 christos esac 266 1.1 jmmv } 267 1.1 jmmv 268 1.1 jmmv # 269 1.1 jmmv # atf_get varname 270 1.1 jmmv # 271 1.1 jmmv # Prints the value of a test case-specific variable. Given that one 272 1.1 jmmv # should not get the value of non-existent variables, it is fine to 273 1.1 jmmv # always use this function as 'val=$(atf_get var)'. 274 1.1 jmmv # 275 1.1 jmmv atf_get() 276 1.1 jmmv { 277 1.1 jmmv eval echo \${__tc_var_${Test_Case}_$(_atf_normalize ${1})} 278 1.1 jmmv } 279 1.1 jmmv 280 1.1 jmmv # 281 1.1 jmmv # atf_get_srcdir 282 1.1 jmmv # 283 1.1 jmmv # Prints the value of the test case's source directory. 284 1.1 jmmv # 285 1.1 jmmv atf_get_srcdir() 286 1.1 jmmv { 287 1.2 christos echo ${Source_Dir} 288 1.1 jmmv } 289 1.1 jmmv 290 1.1 jmmv # 291 1.1 jmmv # atf_pass 292 1.1 jmmv # 293 1.1 jmmv # Makes the test case pass. Shouldn't be used in general, as a test 294 1.1 jmmv # case that does not explicitly fail is assumed to pass. 295 1.1 jmmv # 296 1.1 jmmv atf_pass() 297 1.1 jmmv { 298 1.2 christos case "${Expect}" in 299 1.2 christos fail) 300 1.2 christos Expect=pass 301 1.2 christos atf_fail "Test case was expecting a failure but got a pass instead" 302 1.2 christos ;; 303 1.2 christos pass) 304 1.2 christos _atf_create_resfile passed 305 1.2 christos exit 0 306 1.2 christos ;; 307 1.2 christos *) 308 1.2 christos _atf_error 128 "Unreachable" 309 1.2 christos ;; 310 1.2 christos esac 311 1.1 jmmv } 312 1.1 jmmv 313 1.1 jmmv # 314 1.1 jmmv # atf_require_prog prog 315 1.1 jmmv # 316 1.1 jmmv # Checks that the given program name (either provided as an absolute 317 1.1 jmmv # path or as a plain file name) can be found. If it is not available, 318 1.1 jmmv # automatically skips the test case with an appropriate message. 319 1.1 jmmv # 320 1.1 jmmv # Relative paths are not allowed because the test case cannot predict 321 1.1 jmmv # where it will be executed from. 322 1.1 jmmv # 323 1.1 jmmv atf_require_prog() 324 1.1 jmmv { 325 1.1 jmmv _prog= 326 1.1 jmmv case ${1} in 327 1.1 jmmv /*) 328 1.1 jmmv _prog="${1}" 329 1.1 jmmv [ -x ${_prog} ] || \ 330 1.1 jmmv atf_skip "The required program ${1} could not be found" 331 1.1 jmmv ;; 332 1.1 jmmv */*) 333 1.1 jmmv atf_fail "atf_require_prog does not accept relative path names \`${1}'" 334 1.1 jmmv ;; 335 1.1 jmmv *) 336 1.1 jmmv _prog=$(_atf_find_in_path "${1}") 337 1.1 jmmv [ -n "${_prog}" ] || \ 338 1.1 jmmv atf_skip "The required program ${1} could not be found" \ 339 1.1 jmmv "in the PATH" 340 1.1 jmmv ;; 341 1.1 jmmv esac 342 1.1 jmmv } 343 1.1 jmmv 344 1.1 jmmv # 345 1.1 jmmv # atf_set varname val1 [.. valN] 346 1.1 jmmv # 347 1.1 jmmv # Sets the test case's variable 'varname' to the specified values 348 1.1 jmmv # which are concatenated using a single blank space. This function 349 1.1 jmmv # is supposed to be called form the test case's head only. 350 1.1 jmmv # 351 1.1 jmmv atf_set() 352 1.1 jmmv { 353 1.1 jmmv ${Parsing_Head} || \ 354 1.1 jmmv _atf_error 128 "atf_set called from the test case's body" 355 1.1 jmmv 356 1.1 jmmv Test_Case_Vars="${Test_Case_Vars} ${1}" 357 1.1 jmmv _var=$(_atf_normalize ${1}); shift 358 1.1 jmmv eval __tc_var_${Test_Case}_${_var}=\"\${*}\" 359 1.1 jmmv } 360 1.1 jmmv 361 1.1 jmmv # 362 1.1 jmmv # atf_skip msg1 [.. msgN] 363 1.1 jmmv # 364 1.1 jmmv # Skips the test case because of the reason provided. Multiple words 365 1.1 jmmv # can be given, in which case they are joined by a single blank space. 366 1.1 jmmv # 367 1.1 jmmv atf_skip() 368 1.1 jmmv { 369 1.2 christos _atf_create_resfile "skipped: ${*}" 370 1.1 jmmv exit 0 371 1.1 jmmv } 372 1.1 jmmv 373 1.1 jmmv # 374 1.2 christos # atf_test_case tc-name cleanup 375 1.1 jmmv # 376 1.1 jmmv # Defines a new test case named tc-name. The name provided here must be 377 1.1 jmmv # accompanied by two functions named after it: <tc-name>_head and 378 1.2 christos # <tc-name>_body. If cleanup is set to 'cleanup', then this also expects 379 1.2 christos # a <tc-name>_cleanup function to be defined. 380 1.1 jmmv # 381 1.1 jmmv atf_test_case() 382 1.1 jmmv { 383 1.1 jmmv eval "${1}_head() { :; }" 384 1.2 christos eval "${1}_body() { atf_fail 'Test case not implemented'; }" 385 1.2 christos if [ "${2}" = cleanup ]; then 386 1.2 christos eval __has_cleanup_${1}=true 387 1.2 christos eval "${1}_cleanup() { :; }" 388 1.2 christos else 389 1.2 christos eval "${1}_cleanup() { 390 1.2 christos _atf_error 1 'Test case ${1} declared without a cleanup routine'; }" 391 1.2 christos fi 392 1.1 jmmv } 393 1.1 jmmv 394 1.1 jmmv # ------------------------------------------------------------------------ 395 1.1 jmmv # PRIVATE INTERFACE 396 1.1 jmmv # ------------------------------------------------------------------------ 397 1.1 jmmv 398 1.1 jmmv # 399 1.1 jmmv # _atf_config_set varname val1 [.. valN] 400 1.1 jmmv # 401 1.1 jmmv # Sets the test case's private variable 'varname' to the specified 402 1.1 jmmv # values which are concatenated using a single blank space. 403 1.1 jmmv # 404 1.1 jmmv _atf_config_set() 405 1.1 jmmv { 406 1.1 jmmv _var=$(_atf_normalize ${1}); shift 407 1.1 jmmv eval __tc_config_var_${_var}=\"\${*}\" 408 1.1 jmmv Config_Vars="${Config_Vars} __tc_config_var_${_var}" 409 1.1 jmmv } 410 1.1 jmmv 411 1.1 jmmv # 412 1.1 jmmv # _atf_config_set_str varname=val 413 1.1 jmmv # 414 1.1 jmmv # Sets the test case's private variable 'varname' to the specified 415 1.1 jmmv # value. The parameter is of the form 'varname=val'. 416 1.1 jmmv # 417 1.1 jmmv _atf_config_set_from_str() 418 1.1 jmmv { 419 1.1 jmmv _oldifs=${IFS} 420 1.1 jmmv IFS='=' 421 1.1 jmmv set -- ${*} 422 1.1 jmmv _var=${1} 423 1.1 jmmv shift 424 1.1 jmmv _val="${@}" 425 1.1 jmmv IFS=${_oldifs} 426 1.1 jmmv _atf_config_set "${_var}" "${_val}" 427 1.1 jmmv } 428 1.1 jmmv 429 1.1 jmmv # 430 1.2 christos # _atf_create_resfile contents 431 1.1 jmmv # 432 1.2 christos # Creates the results file. 433 1.1 jmmv # 434 1.2 christos _atf_create_resfile() 435 1.1 jmmv { 436 1.2 christos if [ -n "${Results_File}" ]; then 437 1.2 christos echo "${*}" >"${Results_File}" || \ 438 1.2 christos _atf_error 128 "Cannot create results file '${Results_File}'" 439 1.2 christos else 440 1.2 christos echo "${*}" 441 1.2 christos fi 442 1.1 jmmv } 443 1.1 jmmv 444 1.1 jmmv # 445 1.1 jmmv # _atf_error error_code [msg1 [.. msgN]] 446 1.1 jmmv # 447 1.1 jmmv # Prints the given error message (which can be composed of multiple 448 1.1 jmmv # arguments, in which case are joined by a single space) and exits 449 1.1 jmmv # with the specified error code. 450 1.1 jmmv # 451 1.1 jmmv # This must not be used by test programs themselves (hence making 452 1.1 jmmv # the function private) to indicate a test case's failure. They 453 1.1 jmmv # have to use the atf_fail function. 454 1.1 jmmv # 455 1.1 jmmv _atf_error() 456 1.1 jmmv { 457 1.1 jmmv _error_code="${1}"; shift 458 1.1 jmmv 459 1.2 christos echo "${Prog_Name}: ERROR:" "$@" 1>&2 460 1.1 jmmv exit ${_error_code} 461 1.1 jmmv } 462 1.1 jmmv 463 1.1 jmmv # 464 1.2 christos # _atf_warning msg1 [.. msgN] 465 1.2 christos # 466 1.2 christos # Prints the given warning message (which can be composed of multiple 467 1.2 christos # arguments, in which case are joined by a single space). 468 1.2 christos # 469 1.2 christos _atf_warning() 470 1.2 christos { 471 1.2 christos echo "${Prog_Name}: WARNING:" "$@" 1>&2 472 1.2 christos } 473 1.2 christos 474 1.2 christos # 475 1.1 jmmv # _atf_find_in_path program 476 1.1 jmmv # 477 1.1 jmmv # Looks for a program in the path and prints the full path to it or 478 1.1 jmmv # nothing if it could not be found. It also returns true in case of 479 1.1 jmmv # success. 480 1.1 jmmv # 481 1.1 jmmv _atf_find_in_path() 482 1.1 jmmv { 483 1.1 jmmv _prog="${1}" 484 1.1 jmmv 485 1.1 jmmv _oldifs=${IFS} 486 1.1 jmmv IFS=: 487 1.1 jmmv for _dir in ${PATH} 488 1.1 jmmv do 489 1.1 jmmv if [ -x ${_dir}/${_prog} ]; then 490 1.1 jmmv IFS=${_oldifs} 491 1.1 jmmv echo ${_dir}/${_prog} 492 1.1 jmmv return 0 493 1.1 jmmv fi 494 1.1 jmmv done 495 1.1 jmmv IFS=${_oldifs} 496 1.1 jmmv 497 1.1 jmmv return 1 498 1.1 jmmv } 499 1.1 jmmv 500 1.1 jmmv # 501 1.1 jmmv # _atf_has_tc name 502 1.1 jmmv # 503 1.1 jmmv # Returns true if the given test case exists. 504 1.1 jmmv # 505 1.1 jmmv _atf_has_tc() 506 1.1 jmmv { 507 1.1 jmmv for _tc in ${Test_Cases}; do 508 1.2 christos [ "${_tc}" != "${1}" ] || return 0 509 1.1 jmmv done 510 1.1 jmmv return 1 511 1.1 jmmv } 512 1.1 jmmv 513 1.1 jmmv # 514 1.1 jmmv # _atf_list_tcs 515 1.1 jmmv # 516 1.1 jmmv # Describes all test cases and prints the list to the standard output. 517 1.1 jmmv # 518 1.1 jmmv _atf_list_tcs() 519 1.1 jmmv { 520 1.1 jmmv echo 'Content-Type: application/X-atf-tp; version="1"' 521 1.1 jmmv echo 522 1.1 jmmv 523 1.1 jmmv set -- ${Test_Cases} 524 1.1 jmmv while [ ${#} -gt 0 ]; do 525 1.1 jmmv _atf_parse_head ${1} 526 1.1 jmmv 527 1.1 jmmv echo "ident: $(atf_get ident)" 528 1.1 jmmv for _var in ${Test_Case_Vars}; do 529 1.4 christos # Elide ksh bug! 530 1.4 christos set +e 531 1.1 jmmv [ "${_var}" != "ident" ] && echo "${_var}: $(atf_get ${_var})" 532 1.4 christos set -e 533 1.1 jmmv done 534 1.1 jmmv 535 1.1 jmmv [ ${#} -gt 1 ] && echo 536 1.1 jmmv shift 537 1.1 jmmv done 538 1.1 jmmv } 539 1.1 jmmv 540 1.1 jmmv # 541 1.1 jmmv # _atf_normalize str 542 1.1 jmmv # 543 1.1 jmmv # Normalizes a string so that it is a valid shell variable name. 544 1.1 jmmv # 545 1.1 jmmv _atf_normalize() 546 1.1 jmmv { 547 1.5 kre while : 548 1.5 kre do 549 1.5 kre case "${1}" in 550 1.5 kre (*.*) set -- "${1%.*}_${1##*.}";; 551 1.5 kre (*-*) set -- "${1%-*}_${1##*-}";; 552 1.5 kre (*) break;; 553 1.5 kre esac 554 1.5 kre done 555 1.5 kre printf "%s\n" "$1" 556 1.1 jmmv } 557 1.1 jmmv 558 1.1 jmmv # 559 1.1 jmmv # _atf_parse_head tcname 560 1.1 jmmv # 561 1.1 jmmv # Evaluates a test case's head to gather its variables and prepares the 562 1.1 jmmv # test program to run it. 563 1.1 jmmv # 564 1.1 jmmv _atf_parse_head() 565 1.1 jmmv { 566 1.1 jmmv Parsing_Head=true 567 1.1 jmmv 568 1.1 jmmv Test_Case="${1}" 569 1.1 jmmv Test_Case_Vars= 570 1.1 jmmv 571 1.2 christos if _atf_has_cleanup "${1}"; then 572 1.2 christos atf_set has.cleanup "true" 573 1.2 christos fi 574 1.2 christos 575 1.2 christos ${1}_head 576 1.1 jmmv atf_set ident "${1}" 577 1.1 jmmv 578 1.1 jmmv Parsing_Head=false 579 1.1 jmmv } 580 1.1 jmmv 581 1.1 jmmv # 582 1.1 jmmv # _atf_run_tc tc 583 1.1 jmmv # 584 1.1 jmmv # Runs the specified test case. Prints its exit status to the 585 1.1 jmmv # standard output and returns a boolean indicating if the test was 586 1.1 jmmv # successful or not. 587 1.1 jmmv # 588 1.1 jmmv _atf_run_tc() 589 1.1 jmmv { 590 1.1 jmmv case ${1} in 591 1.1 jmmv *:*) 592 1.1 jmmv _tcname=${1%%:*} 593 1.1 jmmv _tcpart=${1#*:} 594 1.1 jmmv 595 1.1 jmmv if [ "${_tcpart}" != body -a "${_tcpart}" != cleanup ]; then 596 1.1 jmmv _atf_syntax_error "Unknown test case part \`${_tcpart}'" 597 1.1 jmmv fi 598 1.1 jmmv ;; 599 1.1 jmmv 600 1.1 jmmv *) 601 1.1 jmmv _tcname=${1} 602 1.1 jmmv _tcpart=body 603 1.1 jmmv ;; 604 1.1 jmmv esac 605 1.1 jmmv 606 1.2 christos _atf_has_tc "${_tcname}" || _atf_syntax_error "Unknown test case \`${1}'" 607 1.1 jmmv 608 1.2 christos if [ "${__RUNNING_INSIDE_ATF_RUN}" != "internal-yes-value" ]; then 609 1.2 christos _atf_warning "Running test cases without atf-run(1) is unsupported" 610 1.2 christos _atf_warning "No isolation nor timeout control is being applied;" \ 611 1.2 christos "you may get unexpected failures; see atf-test-case(4)" 612 1.1 jmmv fi 613 1.1 jmmv 614 1.2 christos _atf_parse_head ${_tcname} 615 1.1 jmmv 616 1.2 christos case ${_tcpart} in 617 1.2 christos body) 618 1.2 christos if ${_tcname}_body; then 619 1.2 christos _atf_validate_expect 620 1.2 christos _atf_create_resfile passed 621 1.2 christos else 622 1.2 christos Expect=pass 623 1.2 christos atf_fail "Test case body returned a non-ok exit code, but" \ 624 1.2 christos "this is not allowed" 625 1.2 christos fi 626 1.2 christos ;; 627 1.2 christos cleanup) 628 1.2 christos if _atf_has_cleanup "${_tcname}"; then 629 1.2 christos ${_tcname}_cleanup || _atf_error 128 "The test case cleanup" \ 630 1.2 christos "returned a non-ok exit code, but this is not allowed" 631 1.2 christos fi 632 1.2 christos ;; 633 1.2 christos *) 634 1.2 christos _atf_error 128 "Unknown test case part" 635 1.2 christos ;; 636 1.2 christos esac 637 1.1 jmmv } 638 1.1 jmmv 639 1.1 jmmv # 640 1.1 jmmv # _atf_syntax_error msg1 [.. msgN] 641 1.1 jmmv # 642 1.1 jmmv # Formats and prints a syntax error message and terminates the 643 1.1 jmmv # program prematurely. 644 1.1 jmmv # 645 1.1 jmmv _atf_syntax_error() 646 1.1 jmmv { 647 1.2 christos echo "${Prog_Name}: ERROR: ${@}" 1>&2 648 1.2 christos echo "${Prog_Name}: See atf-test-program(1) for usage details." 1>&2 649 1.1 jmmv exit 1 650 1.1 jmmv } 651 1.1 jmmv 652 1.1 jmmv # 653 1.2 christos # _atf_has_cleanup tc-name 654 1.1 jmmv # 655 1.2 christos # Returns a boolean indicating if the given test case has a cleanup 656 1.2 christos # routine or not. 657 1.1 jmmv # 658 1.2 christos _atf_has_cleanup() 659 1.1 jmmv { 660 1.2 christos _found=true 661 1.2 christos eval "[ x\"\${__has_cleanup_${1}}\" = xtrue ] || _found=false" 662 1.2 christos [ "${_found}" = true ] 663 1.1 jmmv } 664 1.1 jmmv 665 1.1 jmmv # 666 1.2 christos # _atf_validate_expect 667 1.1 jmmv # 668 1.2 christos # Ensures that the current test case state is correct regarding the expect 669 1.2 christos # status. 670 1.1 jmmv # 671 1.2 christos _atf_validate_expect() 672 1.1 jmmv { 673 1.2 christos case "${Expect}" in 674 1.2 christos death) 675 1.2 christos Expect=pass 676 1.2 christos atf_fail "Test case was expected to terminate abruptly but it" \ 677 1.2 christos "continued execution" 678 1.2 christos ;; 679 1.2 christos exit) 680 1.2 christos Expect=pass 681 1.2 christos atf_fail "Test case was expected to exit cleanly but it continued" \ 682 1.2 christos "execution" 683 1.2 christos ;; 684 1.2 christos fail) 685 1.2 christos Expect=pass 686 1.2 christos atf_fail "Test case was expecting a failure but none were raised" 687 1.2 christos ;; 688 1.2 christos pass) 689 1.2 christos ;; 690 1.2 christos signal) 691 1.2 christos Expect=pass 692 1.2 christos atf_fail "Test case was expected to receive a termination signal" \ 693 1.2 christos "but it continued execution" 694 1.2 christos ;; 695 1.2 christos timeout) 696 1.2 christos Expect=pass 697 1.2 christos atf_fail "Test case was expected to hang but it continued execution" 698 1.2 christos ;; 699 1.2 christos *) 700 1.2 christos _atf_error 128 "Unreachable" 701 1.2 christos ;; 702 1.2 christos esac 703 1.1 jmmv } 704 1.1 jmmv 705 1.1 jmmv # 706 1.1 jmmv # _atf_warning [msg1 [.. msgN]] 707 1.1 jmmv # 708 1.1 jmmv # Prints the given warning message (which can be composed of multiple 709 1.1 jmmv # arguments, in which case are joined by a single space). 710 1.1 jmmv # 711 1.1 jmmv # This must not be used by test programs themselves (hence making 712 1.1 jmmv # the function private). 713 1.1 jmmv # 714 1.1 jmmv _atf_warning() 715 1.1 jmmv { 716 1.2 christos echo "${Prog_Name}: WARNING:" "$@" 1>&2 717 1.1 jmmv } 718 1.1 jmmv 719 1.1 jmmv # 720 1.1 jmmv # main [options] test_case 721 1.1 jmmv # 722 1.1 jmmv # Test program's entry point. 723 1.1 jmmv # 724 1.1 jmmv main() 725 1.1 jmmv { 726 1.1 jmmv # Process command-line options first. 727 1.1 jmmv _numargs=${#} 728 1.1 jmmv _lflag=false 729 1.2 christos while getopts :lr:s:v: arg; do 730 1.1 jmmv case ${arg} in 731 1.1 jmmv l) 732 1.1 jmmv _lflag=true 733 1.1 jmmv ;; 734 1.1 jmmv 735 1.1 jmmv r) 736 1.1 jmmv Results_File=${OPTARG} 737 1.1 jmmv ;; 738 1.1 jmmv 739 1.1 jmmv s) 740 1.1 jmmv Source_Dir=${OPTARG} 741 1.1 jmmv ;; 742 1.1 jmmv 743 1.1 jmmv v) 744 1.1 jmmv _atf_config_set_from_str "${OPTARG}" 745 1.1 jmmv ;; 746 1.1 jmmv 747 1.1 jmmv \?) 748 1.1 jmmv _atf_syntax_error "Unknown option -${OPTARG}." 749 1.1 jmmv # NOTREACHED 750 1.1 jmmv ;; 751 1.1 jmmv esac 752 1.1 jmmv done 753 1.1 jmmv shift `expr ${OPTIND} - 1` 754 1.1 jmmv 755 1.1 jmmv # First of all, make sure that the source directory is correct. It 756 1.1 jmmv # doesn't matter if the user did not change it, because the default 757 1.1 jmmv # value may not work. (TODO: It possibly should, even though it is 758 1.1 jmmv # not a big deal because atf-run deals with this.) 759 1.1 jmmv case ${Source_Dir} in 760 1.1 jmmv /*) 761 1.1 jmmv ;; 762 1.1 jmmv *) 763 1.1 jmmv Source_Dir=$(pwd)/${Source_Dir} 764 1.1 jmmv ;; 765 1.1 jmmv esac 766 1.1 jmmv [ -f ${Source_Dir}/${Prog_Name} ] || \ 767 1.1 jmmv _atf_error 1 "Cannot find the test program in the source" \ 768 1.1 jmmv "directory \`${Source_Dir}'" 769 1.1 jmmv 770 1.1 jmmv # Call the test program's hook to register all available test cases. 771 1.1 jmmv atf_init_test_cases 772 1.1 jmmv 773 1.1 jmmv # Run or list test cases. 774 1.1 jmmv if `${_lflag}`; then 775 1.1 jmmv if [ ${#} -gt 0 ]; then 776 1.1 jmmv _atf_syntax_error "Cannot provide test case names with -l" 777 1.1 jmmv fi 778 1.1 jmmv _atf_list_tcs 779 1.1 jmmv else 780 1.1 jmmv if [ ${#} -eq 0 ]; then 781 1.1 jmmv _atf_syntax_error "Must provide a test case name" 782 1.1 jmmv elif [ ${#} -gt 1 ]; then 783 1.1 jmmv _atf_syntax_error "Cannot provide more than one test case name" 784 1.1 jmmv else 785 1.1 jmmv _atf_run_tc "${1}" 786 1.1 jmmv fi 787 1.1 jmmv fi 788 1.1 jmmv } 789 1.1 jmmv 790 1.1 jmmv # vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4 791