1 #
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 # ident "@(#)util_common.ksh    1.2     08/12/19 SMI"
  28 #
  29 
  30 #
  31 # Common utilities for test functions
  32 #
  33 
  34 TMPDIR=/tmp
  35 EXECUTION_RECORD=${TMPDIR}/execution_record_$$
  36 
  37 
  38 #
  39 # NAME:
  40 #       delete_execution_record
  41 #
  42 # SYNOPSIS:
  43 #       delete_execution_record
  44 #
  45 # DESCRIPTION:
  46 #       Delete the file created to contain the record of commands executed.
  47 #
  48 # RETURN VALUE:
  49 #       Undefined (not set)
  50 #
  51 function delete_execution_record {
  52         $RM -f $EXECUTION_RECORD 2>/dev/null
  53 }
  54 
  55 
  56 #
  57 # NAME:
  58 #       display_execution_record
  59 #
  60 # SYNOPSIS:
  61 #       display_execution_record
  62 #
  63 # DESCRIPTION:
  64 #       Show the contents of the file containing a record of commands executed
  65 #       by a test case.  A header and footer are printed to visually separate
  66 #       the output from the rest of the journal file.  This function is
  67 #       typically called by a failed test purpose in order to display the
  68 #       exact list of commands that were executed.  (Note:  Do to the
  69 #       mysteries of how UNIX shells work, it's not unusual for output from
  70 #       actions taken before or after this function is called to be mixed
  71 #       in with the output of this function in the journal file.)
  72 #
  73 # RETURN VALUE:
  74 #       Undefined (not set)
  75 #
  76 function display_execution_record {
  77         if [[ -z "$EXECUTION_RECORD" ]]; then
  78                 return
  79         fi
  80 
  81         typeset output=${TMPDIR}/final_execution_record_$$
  82         echo "------Record of commands executed------" >$output
  83         echo "Phase      Command" >>$output
  84         echo "---------  ----------------------------" >> $output
  85         cat $EXECUTION_RECORD >> $output
  86         echo "------End of cmd execution record------" >> $output
  87         cti_reportfile $output
  88         $RM -f $output 2>/dev/null
  89         delete_execution_record
  90 }
  91 
  92 
  93 #
  94 # NAME:
  95 #       create_execution_record
  96 #
  97 # SYNOPSIS:
  98 #       create_execution_record
  99 #
 100 # DESCRIPTION:
 101 #       Create the file to contain the record of commands executed, after
 102 #       first deleting any pre-existing file.  This function is typically
 103 #       called at the beginning of a test purpose, to create/clean-out
 104 #       the file that contains the record of commands executed.
 105 #
 106 # RETURN VALUE:
 107 #       Not set
 108 #
 109 function create_execution_record {
 110         if [[ -z "$EXECUTION_RECORD" ]]; then
 111                 return
 112         fi
 113 
 114         delete_execution_record
 115         touch $EXECUTION_RECORD
 116 }
 117 
 118 
 119 #
 120 # NAME:
 121 #       record_cmd_execution
 122 #
 123 # SYNOPSIS:
 124 #       record_cmd_execution <command>
 125 #
 126 # DESCRIPTION:
 127 #       Copy the specified command into the record of commands executed.
 128 #
 129 #       This function is intended to be used to build a record of the
 130 #       commands executed during the course of a test purpose.  The tp
 131 #       function, as well as utility functions it calls that execute
 132 #       commands, should call this function for each command they execute.
 133 #       The resulting record of commands can then be displayed if the test
 134 #       purpose fails, providing a list of the exact commands executed as
 135 #       an aid in reproducing/troubleshooting the failure.
 136 #
 137 # RETURN VALUE:
 138 #       Not set
 139 #
 140 function record_cmd_execution {
 141         if [[ -z "$EXECUTION_RECORD" ]]; then
 142                 return
 143         fi
 144 
 145         echo "${ex_phase}  $*" >> $EXECUTION_RECORD
 146 }
 147 
 148 
 149 #
 150 # NAME:
 151 #       execution_phase_setup
 152 #
 153 # SYNOPSIS:
 154 #       execution_phase_setup
 155 #
 156 # DESCRIPTION:
 157 #       Set the current execution phase (used by the record_execution_record)
 158 #       function to 'setup'.
 159 #
 160 # RETURN VALUE:
 161 #       Not set
 162 #
 163 function execution_phase_setup {
 164         ex_phase="setup    "
 165 }
 166 
 167 
 168 #
 169 # NAME:
 170 #       execution_phase_assert
 171 #
 172 # SYNOPSIS:
 173 #       execution_phase_assert
 174 #
 175 # DESCRIPTION:
 176 #       Set the current execution phase (used by the record_execution_record)
 177 #       function to 'assert'.
 178 #
 179 # RETURN VALUE:
 180 #       Not set
 181 #
 182 function execution_phase_assert {
 183         ex_phase="assertion"
 184 }
 185 
 186 
 187 #
 188 # NAME:
 189 #       execution_phase_cleanup
 190 #
 191 # SYNOPSIS:
 192 #       execution_phase_cleanup
 193 #
 194 # DESCRIPTION:
 195 #       Set the current execution phase (used by the record_execution_record)
 196 #       function to 'cleanup'.
 197 #
 198 # RETURN VALUE:
 199 #       Not set
 200 #
 201 function execution_phase_cleanup {
 202         ex_phase="cleanup  "
 203 }
 204 
 205 
 206 #
 207 # NAME:
 208 #        extract_assertion_info
 209 #
 210 # SYNOPSIS:
 211 #       extract_assertion_info <test_source_filename>
 212 #
 213 # DESCRIPTION:
 214 #       A function to extract the assertion information from the test source
 215 #       file. It prints out the assertion information in a standard format to
 216 #       stdout (and thus to the journal file). 
 217 #
 218 #       
 219 # ARGUMENTS:
 220 #       $1 - the file where the header information is. Typically this is the
 221 #            test case source file.
 222 #       $2 - this optional argument identifies a specific assertion for a file
 223 #            that contains multiple assertions.  If provided, only this
 224 #            assertion will be extracted.
 225 #
 226 # RETURNS:
 227 #       No return code is set.  The function prints information to stdout
 228 #       (and thus to the journal file).
 229 #
 230 function extract_assertion_info {
 231 
 232         typeset tmpfile=${TMPDIR}/extract_assertion_info_$$
 233 
 234         # Extract the assertion info from the test source file and
 235         # place it in a temporary file.
 236         nawk -v specific_assert=$2 '
 237 
 238  BEGIN {
 239                 in_assertion        = 0;
 240                 turn_off_printing       = 0;
 241         }
 242 
 243 
 244         #
 245         # End of the .spec content. This finds the end of the assertion
 246         #
 247         /^# +end +__stc_assertion/ {
 248                 in_assertion = 0;
 249                 next;
 250         }
 251 
 252 
 253 
 254         #
 255         # Beginning of the .spec content. This finds the beginning
 256         # of the assertion.
 257         #
 258         /^# +start +__stc_assertion__/ {
 259                 in_assertion = 1;
 260                 next;
 261         }
 262 
 263 
 264         #
 265         # This grabs the "ASSERTION: testname" line.  If no specific
 266         # assertion was identified we will grab any "ASSERTION:" line we
 267         # find.  If a specific assertion was identified, make sure the
 268         # "ASSERTION:" line matches it -- if not, this assertion is not
 269         # the one we are looking for.
 270         #
 271         /^.+ASSERTION:/ && (in_assertion) {
 272                 if ( specific_assert == "" || specific_assert == $NF ) {
 273                         a=substr($0, index($0, "#") + length("#"));
 274                         #remove any leading spaces
 275                         sub(/^ +/, "", a);
 276                         printf("%s\n\n", a);
 277                         turn_off_printing = 1;
 278                         next;
 279                 } else {
 280                         in_assertion = 0;
 281                 }
 282         }
 283 
 284         #
 285         # This prints the actual assertion statement. STC calls this the
 286         # description and requires one for every ASSERTION:.
 287 
 288         #
 289         /^.+DESCRIPTION:/ && (in_assertion) {
 290             a=substr($0, index($0, "DESCRIPTION:") + length("DESCRIPTION:"));
 291                 a=substr($0, index($0, "#") + length("#"));
 292                 #remove any leading spaces
 293                 sub(/^ +/, "", a);
 294                 printf("%s\n\n", a);
 295                turn_off_printing = 0;
 296                next;
 297         }
 298 
 299         #
 300         # List of interfaces targeted by the current assertion. STC requires
 301         # one of these for every ASSERTION:
 302         #
 303         #/^.+INTERFACES:/ && (in_assertion) {
 304         #       in_assertion = 0;
 305         #}
 306 
 307         /^.+STRATEGY:/ && (in_assertion) {
 308                 #use in_assertion =1 to print the strategy.
 309                 in_assertion = 0;
 310 
 311                 #use in_assertion =1 to print the strategy.
 312                 in_assertion = 0;
 313         }
 314 
 315         # Body of the assertion comments.
 316         #
 317         (in_assertion) && length && !(turn_off_printing) {
 318                 a=substr($0,index($0,"#")+1);
 319                 printf("%s\n", a);
 320         }
 321 
 322         ' $1 > $tmpfile
 323 
 324         # Copy the extracted information into the journal and then
 325         # clean up after ourselves.
 326         cti_reportfile $tmpfile
 327         rm -rf $tmpfile
 328 }
 329 
 330 
 331 #
 332 # NAME:
 333 #       extract_line_from_file
 334 #
 335 # SYNOPSIS:
 336 #       extract_line_from_file <filename> <line number>
 337 #
 338 # DESCRIPTION:
 339 #       Verify that the specified file exists and is readable, then extract
 340 #       the specified line from the file.  The line extracted is echoed to
 341 #       stdout so that it can be captured by the calling function.
 342 #
 343 # RETURN VALUES:
 344 #       0       Successfully extracted the specified line from the file.
 345 #       1       Unable to access file.
 346 #       2       Could not locate the specified line in the file.
 347 #
 348 function extract_line_from_file {
 349         typeset filename="$1"
 350         typeset line_number="$2"
 351 
 352         # Make sure the file exists and is readable.
 353         if [[ ! -r "$filename" ]]; then
 354                 cti_report "File $filename doesn't exist or isn't readable" \
 355                     "by this process"
 356                 return 1
 357         fi
 358 
 359         # Read in each line of the file until we've obtained the Nth line
 360         # (where N equals the argument passed in specifying the desired line
 361         # number).
 362         typeset line_num=0
 363         typeset matching_line=""
 364         { while read line; do
 365                 let line_num=$line_num+1
 366                 if (( $line_num == $line_number )); then
 367                         matching_line="$line"
 368                         break
 369                 fi
 370         done } < $filename
 371 
 372         # Make sure we actually obtained something.
 373         if [[ -z "$matching_line" ]]; then
 374                 cti_report "Unable to find line number $line_number in file" \
 375                     "$filename"
 376                 return 2
 377         fi
 378 
 379         # Print the line to stdout so that the calling function can capture it.
 380         echo $matching_line
 381 
 382         return 0
 383 }
 384 
 385 
 386 #
 387 # NAME
 388 #       tp_within_parameters
 389 #
 390 # SYNOPSIS
 391 #       tp_within_parameters <list name> <param> [<list name> <param> ...]
 392 #
 393 # DESCRIPTION
 394 #       This function was designed primarily for use by dynamically generated
 395 #       tests.  In these tests the same test purposes is reused multiple
 396 #       times, executing with a different combination of parameter values each
 397 #       time.  The suite allows users to restrict which parameters values are
 398 #       desired by setting variables in the file:
 399 #
 400 #               $TET_SUITE_ROOT/lofi/config/test_config
 401 #
 402 #       (or by making the same variable assignments on the command line).
 403 #       This function is called by such test purposes to determine if the
 404 #       set of parameters for the current iteration fits within any
 405 #       restrictions the user might have set.
 406 #
 407 #       For each parameter the test purpose is concerned about, it passes in
 408 #       the name of the variable containing the list of desired parameters
 409 #       along with the current value of that parameter.  If the list variable
 410 #       specified is not set then the user has not placed restrictions on that
 411 #       particular parameter.  If the variable is set, then the function
 412 #       compares the current parameter value against the list of desired
 413 #       values.  If the parameter value is not on the 'desired' list the test
 414 #       purpose should not be run.
 415 #
 416 #       Multiple parameter lists and current values can be specified in one
 417 #       call to this function (see SYNOPSIS).  The function evaluates all of
 418 #       them, and if any one parameter value is found to be missing from the
 419 #       corresponding list of desired values then the function calls
 420 #       cti_unsupported() and gives a return value of 1.  When this happens,
 421 #       the calling test purpose should return immediately.
 422 #
 423 #       Note that while this function was written for test purposes using
 424 #       dynamically-generated test parameters, static test purposes can make
 425 #       use of it as well.
 426 #
 427 # RETURN VALUES
 428 #       0       Test purpose fits within current paramters and should be run
 429 #       1       Test purpose doesn't fit current parameters and should not run
 430 function tp_within_parameters {
 431 
 432         typeset param_list_name param_list current_param match
 433         typeset status=0
 434 
 435         while [[ -n "$@" ]]; do
 436                 # Extract first variable name and current parameter value from
 437                 # the head of the list.
 438                 unset match
 439                 param_list_name="$1"
 440                 current_param="$2"
 441                 shift 2
 442 
 443                 # Use 'eval' to get at the contents of the specified variable,
 444                 # which will provide us with the list of desired values.
 445                 eval param_list=\$$param_list_name
 446 
 447                 # If the list of desired values is empty, the user placed no
 448                 # restrictions on this paramter and we can skip over it.  If
 449                 # the list isn't empty, see if the current parameter value is
 450                 # on the 'desired' list.
 451                 if [[ -n "$param_list" ]]; then
 452                         for param in $param_list; do
 453                                 if [[ "$param" = "$current_param" ]]; then
 454                                         match=1
 455                                 fi
 456                         done
 457                         if [[ -z "$match" ]]; then
 458                                 cti_report "Parameter '$current_param' not" \
 459                                     "in $param_list_name ('$param_list')"
 460                                 status=1
 461                         fi
 462                 fi
 463         done
 464 
 465         if (( $status != 0 )); then
 466                 cti_untested "Test purpose does not fit user-defined" \
 467                     "execution criteria"
 468         fi
 469         return $status
 470 }