# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Name: testing.sh - part of the BeakerLib project
# Description: Asserting functions, watchdog and report
#
# Author: Ondrej Hudlicky <ohudlick@redhat.com>
# Author: Petr Muller <pmuller@redhat.com>
# Author: Jan Hutar <jhutar@redhat.com>
# Author: Petr Splichal <psplicha@redhat.com>
# Author: Ales Zelinka <azelinka@redhat.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2008-2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing
# to use, modify, copy, or redistribute it subject to the terms
# and conditions of the GNU General Public License version 2.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export __INTERNAL_DEFAULT_REPORT_RESULT=/bin/true
: <<'=cut'
=pod
=head1 NAME
BeakerLib - testing - asserting functions, watchdog and report
=head1 DESCRIPTION
This file contains functions related directly to testing. These functions are
various asserts affecting final result of the phase. Watchdog and the report
result function is included as well.
=head1 FUNCTIONS
=cut
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Internal Stuff
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
. $BEAKERLIB/logging.sh
. $BEAKERLIB/journal.sh
__INTERNAL_LogAndJournalPass() {
rljAddTest "$1 $2" "PASS" "$3"
}
__INTERNAL_LogAndJournalFail() {
rljAddTest "$1 $2" "FAIL" "$3"
}
# __INTERNAL_ConditionalAssert comment status [failed-comment] [executed command-line]
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__INTERNAL_ConditionalAssert() {
if [ "$2" == "0" ]; then
__INTERNAL_LogAndJournalPass "$1" "$3" "$4"
return 0
else
__INTERNAL_LogAndJournalFail "$1" "$3" "$4"
return 1
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlPass
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Manual Asserts
=head3 rlPass
Manual assertion, asserts and logs PASS.
rlPass comment
=over
=item comment
Short test summary.
=back
Returns 0 and asserts PASS.
=cut
rlPass() {
__INTERNAL_LogAndJournalPass "$1"
return 0
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlFail
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlFail
Manual assertion, asserts and logs FAIL.
rlFail comment
=over
=item comment
Short test summary.
=back
Returns 1 and asserts FAIL.
=cut
rlFail() {
__INTERNAL_LogAndJournalFail "$1"
return 1
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssert0
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Arithmetic Asserts
=head3 rlAssert0
Assertion checking for the equality of parameter to zero.
rlAssert0 comment value
=over
=item comment
Short test summary, e.g. "Test if compilation ended successfully".
=item value
Integer value (usually return code of a command).
=back
Returns 0 and asserts PASS when C<value == 0>.
=cut
rlAssert0() {
__INTERNAL_ConditionalAssert "$1" "$2" "(Assert: expected 0, got $2)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertEquals
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertEquals
Assertion checking for the equality of two parameters.
rlAssertEquals comment value1 value2
=over
=item comment
Short test summary, e.g. "Test if all 3 packages have been downloaded".
=item value1
First parameter to compare, can be a number or a string
=item value2
Second parameter to compare, can be a number or a string
=back
Returns 0 and asserts PASS when C<value1 == value2>.
=cut
rlAssertEquals() {
if [ $# -lt 3 ] ; then
__INTERNAL_LogAndJournalFail "rlAssertEquals called without all needed parameters" ""
return 1
fi
__INTERNAL_ConditionalAssert "$1" "$([ "$2" == "$3" ]; echo $?)" "(Assert: '$2' should equal '$3')"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotEquals
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotEquals
Assertion checking for the non-equality of two parameters.
rlAssertNotEquals comment value1 value2
=over
=item comment
Short test summary, e.g. "Test if return code is not 139".
=item value1
First parameter to compare, can be a number or a string
=item value2
Second parameter to compare, can be a number or a string
=back
Returns 0 and asserts PASS when C<value1 != value2>.
=cut
rlAssertNotEquals() {
if [ $# -lt 3 ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotEquals called without all needed parameters" ""
return 1
fi
__INTERNAL_ConditionalAssert "$1" "$([ "$2" != "$3" ]; echo $?)" "(Assert: \"$2\" should not equal \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGreater
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGreater
Assertion checking whether first parameter is greater than the second one.
rlAssertGreater comment value1 value2
=over
=item comment
Short test summary, e.g. "Test whether there are running more instances of program."
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<gt> value2>.
=cut
rlAssertGreater() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -gt "$3" ]; echo $?)" "(Assert: \"$2\" should be greater than \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGreaterOrEqual
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGreaterOrEqual
Assertion checking whether first parameter is greater or equal to the second one.
rlAssertGreaterOrEqual comment value1 value2
=over
=item comment
Short test summary (e.g. "There should present at least one...")
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<ge>= value2>.
=cut
rlAssertGreaterOrEqual() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -ge "$3" ]; echo $?)" "(Assert: \"$2\" should be >= \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertLesser
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertLesser
Assertion checking whether first parameter is lesser than the second one.
rlAssertLesser comment value1 value2
=over
=item comment
Short test summary, e.g. "Test whether there are running more instances of program."
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<le> value2>.
=cut
rlAssertLesser() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -le "$3" ]; echo $?)" "(Assert: \"$2\" should be lesser than \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertLesserOrEqual
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertLesserOrEqual
Assertion checking whether first parameter is lesser or equal to the second one.
rlAssertLesserOrEqual comment value1 value2
=over
=item comment
Short test summary (e.g. "There should present at least one...")
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<le>= value2>.
=cut
rlAssertLesserOrEqual() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -le "$3" ]; echo $?)" "(Assert: \"$2\" should be <= \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertExists
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 File Asserts
=head3 rlAssertExists
Assertion checking for the existence of a file or a directory.
rlAssertExists file|directory
=over
=item file|directory
Path to the file or directory.
=back
Returns 0 and asserts PASS when C<file> exists.
=cut
rlAssertExists(){
if [ -z "$1" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertExists called without parameter" ""
return 1
fi
local FILE="File"
if [ -d "$1" ] ; then
FILE="Directory"
fi
__INTERNAL_ConditionalAssert "$FILE $1 should exist" "$([ -e "$1" ]; echo $?)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotExists
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotExists
Assertion checking for the non-existence of a file or a directory.
rlAssertNotExists file|directory
=over
=item file|directory
Path to the file or directory.
=back
Returns 0 and asserts PASS when C<file> does not exist.
=cut
rlAssertNotExists(){
if [ -z "$1" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotExists called without parameter" ""
return 1
fi
local FILE="File"
if [ -d "$1" ] ; then
FILE="Directory"
fi
__INTERNAL_ConditionalAssert "$FILE $1 should not exist" "$([ ! -e "$1" ]; echo $?)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGrep
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGrep
Assertion checking if the file contains a pattern.
rlAssertGrep pattern file [options]
=over
=item pattern
Regular expression to be searched for.
=item file
Path to the file.
=item options
Optional parameters to be passed to grep, default is C<-q>. Can be
used to perform case insensitive matches (-i), or using
extended (-E) or perl (-P) regular expressions.
=back
Returns 0 and asserts PASS when C<file> exists and contains given
C<pattern>.
=cut
rlAssertGrep(){
if [ ! -e "$2" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertGrep: failed to find file $2"
return 2
fi
local options=${3:--q}
grep $options -- "$1" "$2"
__INTERNAL_ConditionalAssert "File '$2' should contain '$1'" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotGrep
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotGrep
Assertion checking that the file does not contain a pattern.
rlAssertNotGrep pattern file [options]
=over
=item pattern
Regular expression to be searched for.
=item file
Path to the file.
=item options
Optional parameters to be passed to grep, default is C<-q>. Can be
used to perform case insensitive matches (-i), or using
extended (-E) or perl (-P) regular expressions.
=back
Returns 0 and asserts PASS when C<file> exists and does not
contain given C<pattern>.
=cut
rlAssertNotGrep(){
if [ ! -e "$2" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotGrep: failed to find file $2"
return 2
fi
local options=${3:--q}
! grep $options -- "$1" "$2"
__INTERNAL_ConditionalAssert "File '$2' should not contain '$1'" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertDiffer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertDiffer
Assertion checking that two files differ (are not identical).
rlAssertDiffer file1 file2
=over
=item file1
Path to first file1
=item file2
Path to second file
=back
Returns 0 and asserts PASS when C<file1> and C<file2> differs.
=cut
rlAssertDiffer(){
local file
for file in "$1" "$2"; do
if [ ! -e "$file" ]; then
__INTERNAL_LogAndJournalFail "rlAssertDiffer: file $file was not found"
return 2
fi
done
! cmp -s "$1" "$2"
__INTERNAL_ConditionalAssert "Files $1 and $2 should differ" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotDiffer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotDiffer
Assertion checking that two files do not differ (are identical).
rlAssertNotDiffer file1 file2
=over
=item file1
Path to first file1
=item file2
Path to second file
=back
Returns 0 and asserts PASS when C<file1> and C<file2> do not differ.
=cut
rlAssertNotDiffer() {
local file
for file in "$1" "$2"; do
if [ ! -e "$file" ]; then
__INTERNAL_LogAndJournalFail "rlAssertNotDiffer: file $file was not found"
return 2
fi
done
cmp -s "$1" "$2"
__INTERNAL_ConditionalAssert "Files $1 and $2 should not differ" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlRun
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Run, Watch, Report
=head3 rlRun
Run command with optional comment and make sure its exit code
matches expectations.
rlRun [-t] [-l] [-c] [-s] command [status[,status...] [comment]]
=over
=item -t
If specified, stdout and stderr of the command output will be tagged
with strigs 'STDOUT: ' and 'STDERR: '.
=item -l
If specified, output of the command (tagged, if -t was specified) is
logged using rlLog function. This is intended for short outputs, and
therefore only last 50 lines are logged this way. Longer outputs should
be analysed separately, or uploaded via rlFileSubmit or rlBundleLogs.
=item -c
Same as C<-l>, but only log the commands output if it failed.
=item -s
Store stdout and stderr to a file (mixed together, as the user would see
it on a terminal) and set $rlRun_LOG variable to name of the file. Caller
is responsible for removing the file. When -t option is used, the content
of the file becomes tagged too.
If the -s option is not used, $rlRun_LOG is not modified and keeps its
content from the last "rlRun -s".
=item command
Command to run.
=item status
Expected exit code(s). Optional, default 0. If you expect more
exit codes, separate them with comma (e.g. "0,1" when both 0 and 1
are OK and expected), or use from-to notation (i.e. "2-5" for "2,3,4,5"),
or combine them (e.g. "2-4,26" for "2,3,4,26").
=item comment
Short summary describing the action (optional, but recommended -
explain what are you doing here).
=back
Returns the exit code of the command run. Asserts PASS when
command\'s exit status is in the list of expected exit codes.
Note:
=over
=item
The output of rlRun is buffered when using C<-t>, C<-l> or C<-s>
option (they use unix pipes, which are buffered by nature). If you
need an unbuffered output just make sure that C<expect> package is
installed on your system (its "unbuffer" tool will automatically
be used to produce unbuffered output).
=item
Be aware that there are some variables which can collide with your code executed
within rlRun. You should avoid using __INTERNAL_rlRun_* variables.
=back
B<Warning:> using C<unbuffer> tool is now disabled because of bug 547686.
=cut
#'
rlRun() {
local __INTERNAL_rlRun_GETOPT=$(getopt -q -o lcts -- "$@")
eval set -- "$__INTERNAL_rlRun_GETOPT"
local __INTERNAL_rlRun_DO_LOG=false
local __INTERNAL_rlRun_DO_TAG=false
local __INTERNAL_rlRun_DO_KEEP=false
local __INTERNAL_rlRun_DO_CON=false
local __INTERNAL_rlRun_TAG_OUT=''
local __INTERNAL_rlRun_TAG_ERR=''
local __INTERNAL_rlRun_LOG_FILE=''
while true ; do
case "$1" in
-l)
__INTERNAL_rlRun_DO_LOG=true;
shift;;
-c)
__INTERNAL_rlRun_DO_LOG=true;
__INTERNAL_rlRun_DO_CON=true;
shift;;
-t)
__INTERNAL_rlRun_DO_TAG=true;
__INTERNAL_rlRun_TAG_OUT='STDOUT: '
__INTERNAL_rlRun_TAG_ERR='STDERR: '
shift;;
-s)
__INTERNAL_rlRun_DO_KEEP=true
shift;;
--)
shift;
break;;
*)
shift;;
esac
done
local __INTERNAL_rlRun_command=$1
local __INTERNAL_rlRun_expected_orig=${2:-0}
local __INTERNAL_rlRun_expected=${2:-0}
local __INTERNAL_rlRun_comment
local __INTERNAL_rlRun_comment_begin
if [[ -z "$3" ]]; then
__INTERNAL_rlRun_comment_begin="Running '$__INTERNAL_rlRun_command'"
__INTERNAL_rlRun_comment="Command '$__INTERNAL_rlRun_command'"
else
__INTERNAL_rlRun_comment_begin="$3 :: actually running '$__INTERNAL_rlRun_command'"
__INTERNAL_rlRun_comment="$3"
fi
# here we can do various sanity checks of the $command
if [[ "$__INTERNAL_rlRun_command" =~ ^[[:space:]]*$ ]] ; then
rlFail "rlRun: got empty or blank command '$__INTERNAL_rlRun_command'!"
return 1
elif false ; then
# this an example check
rlFail "rlRun: sanity check of command '$__INTERNAL_rlRun_command' failed!"
return 1
fi
# create __INTERNAL_rlRun_LOG_FILE if needed
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_KEEP
then
__INTERNAL_rlRun_LOG_FILE=$( mktemp --tmpdir=$__INTERNAL_PERSISTENT_TMP rlRun_LOG.XXXXXXXX )
if [ ! -e "$__INTERNAL_rlRun_LOG_FILE" ]
then
rlFail "rlRun: Internal file creation failed"
rlLogError "rlRun: Please report this issue to RH Bugzilla for Beakerlib component"
rlLogError "rlRun: Turning off any -l, -c or -s options of rlRun"
rlLogError "rlRun: Unless the test relies on them, rest of the test can be trusted."
__INTERNAL_rlRun_DO_LOG=false
__INTERNAL_rlRun_DO_KEEP=false
__INTERNAL_rlRun_LOG_FILE=/dev/null
fi
fi
# in case expected exit code is provided as "2-5,26", expand it to "2,3,4,5,26"
while echo "$__INTERNAL_rlRun_expected" | grep -q '[0-9]-[0-9]'; do
local __INTERNAL_rlRun_interval=$(echo "$__INTERNAL_rlRun_expected" | sed "s/.*\(\<[0-9]\+-[0-9]\+\>\).*/\1/")
if [ -z "$__INTERNAL_rlRun_interval" ]; then
rlLogWarning "rlRun: Something happened when getting interval, using '0-0'"
__INTERNAL_rlRun_interval='0-0'
fi
local __INTERNAL_rlRun_interval_a=$(echo "$__INTERNAL_rlRun_interval" | cut -d '-' -f 1)
local __INTERNAL_rlRun_interval_b=$(echo "$__INTERNAL_rlRun_interval" | cut -d '-' -f 2)
if [ -z "$__INTERNAL_rlRun_interval_a" -o -z "$__INTERNAL_rlRun_interval_b" ]; then
rlLogWarning "rlRun: Something happened when getting boundaries of interval, using '0' and '0'"
__INTERNAL_rlRun_interval_a=0
__INTERNAL_rlRun_interval_b=0
fi
if [ $__INTERNAL_rlRun_interval_a -gt $__INTERNAL_rlRun_interval_b ]; then
rlLogWarning "rlRun: First boundary have to be smaller then second one, using '$__INTERNAL_rlRun_interval_b' and '$__INTERNAL_rlRun_interval_b'"
__INTERNAL_rlRun_interval_a=$__INTERNAL_rlRun_interval_b
fi
local __INTERNAL_rlRun_replacement="$__INTERNAL_rlRun_interval_a"
let __INTERNAL_rlRun_interval_a=$__INTERNAL_rlRun_interval_a+1
local __INTERNAL_rlRun_i
for __INTERNAL_rlRun_i in $(seq $__INTERNAL_rlRun_interval_a $__INTERNAL_rlRun_interval_b); do
__INTERNAL_rlRun_replacement="$__INTERNAL_rlRun_replacement,$__INTERNAL_rlRun_i"
done
__INTERNAL_rlRun_expected="${__INTERNAL_rlRun_expected//$__INTERNAL_rlRun_interval/$__INTERNAL_rlRun_replacement/}"
done
rlLogDebug "rlRun: Running command: $__INTERNAL_rlRun_command"
__INTERNAL_PrintText "$__INTERNAL_rlRun_comment_begin" "BEGIN"
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_TAG || $__INTERNAL_rlRun_DO_KEEP; then
eval "$__INTERNAL_rlRun_command" 2> >(sed -u -e "s/^/$__INTERNAL_rlRun_TAG_ERR/g" |
tee -a $__INTERNAL_rlRun_LOG_FILE) 1> >(sed -u -e "s/^/$__INTERNAL_rlRun_TAG_OUT/g" | tee -a $__INTERNAL_rlRun_LOG_FILE)
local __INTERNAL_rlRun_exitcode=$?
else
eval "$__INTERNAL_rlRun_command"
local __INTERNAL_rlRun_exitcode=$?
fi
rlLogDebug "rlRun: command = '$__INTERNAL_rlRun_command'; exitcode = $__INTERNAL_rlRun_exitcode; expected = $__INTERNAL_rlRun_expected"
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_TAG || $__INTERNAL_rlRun_DO_KEEP; then
sync
fi
echo "$__INTERNAL_rlRun_expected" | grep -q "\<$__INTERNAL_rlRun_exitcode\>" # symbols \< and \> match the empty string at the beginning and end of a word
local __INTERNAL_rlRun_result=$?
if $__INTERNAL_rlRun_DO_LOG && ( ! $__INTERNAL_rlRun_DO_CON || ( $__INTERNAL_rlRun_DO_CON && [ $__INTERNAL_rlRun_result -ne 0 ] ) ); then
rlLog "Output of '$__INTERNAL_rlRun_command':"
rlLog "--------------- OUTPUT START ---------------"
local __INTERNAL_rlRun_line
tail -n 50 "$__INTERNAL_rlRun_LOG_FILE" | while read __INTERNAL_rlRun_line
do
rlLog "$__INTERNAL_rlRun_line"
done
rlLog "--------------- OUTPUT END ---------------"
fi
if $__INTERNAL_rlRun_DO_KEEP; then
rlRun_LOG=$__INTERNAL_rlRun_LOG_FILE
export rlRun_LOG
elif $__INTERNAL_rlRun_DO_LOG; then
rm $__INTERNAL_rlRun_LOG_FILE
fi
rlLogDebug "rlRun: Command finished with exit code: $__INTERNAL_rlRun_exitcode, expected: $__INTERNAL_rlRun_expected_orig"
__INTERNAL_ConditionalAssert "$__INTERNAL_rlRun_comment" $__INTERNAL_rlRun_result "(Expected $__INTERNAL_rlRun_expected_orig, got $__INTERNAL_rlRun_exitcode)" "$__INTERNAL_rlRun_command"
return $__INTERNAL_rlRun_exitcode
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlWatchdog
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlWatchdog
Run C<command>. If it does not finish in specified time, then kill
it using C<signal>.
rlWatchdog command timeout [signal] [callback]
=over
=item command
Command to run.
=item timeout
Timeout to wait, in seconds.
=item signal
Signal to use (optional, default KILL).
=item callback
Callback function to be called before the signal is send (optional, none
by default). The callback function will have one argument available -- PGID
of the process group.
=back
Returns 0 if the command ends normally, without need to be killed.
=cut
rlWatchdog() {
set -m
local command=$1
local timeout=$2
local killer=${3:-"KILL"}
local callback=${4:-""}
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
rlLog "Runnning $command, with $timeout seconds timeout"
eval "$command; touch __INTERNAL_FINISHED" &
local pidcmd=$!
eval "sleep $timeout; touch __INTERNAL_TIMEOUT" &
local pidsleep=$!
while true; do
if [ -e __INTERNAL_FINISHED ]; then
rlLog "Command ended itself, I am not killing it."
/bin/kill -- -$pidsleep
sleep 1
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
return 0
elif [ -e __INTERNAL_TIMEOUT ]; then
rlLog "Command is still running, I am killing it with $killer"
if [ -n "$callback" ] \
&& type $callback 2>/dev/null | grep -q "$callback is a function"
then
rlLog "Function $callback is present, I am calling it"
$callback $pidcmd
fi
/bin/kill -$killer -- -$pidcmd
sleep 1
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
return 1
fi
sleep 1
done
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlReport
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlReport
Report test result to the test harness. The command to be used for
reporting is set by the respective plugin. You can also use the
C<$BEAKERLIB_COMMAND_REPORT_RESULT> variable to use your custom
command.
rlReport name result [score] [log]
=over
=item name
Name of the test result.
=item result
Result (one of PASS, WARN, FAIL). If called with something
else, will use WARN.
=item score
Test score (optional).
=item log
Optional log file to be submitted instead of default C<OUTPUTFILE>.
=back
=cut
rlReport() {
# only PASS/WARN/FAIL is allowed
local testname="$1"
local result="$(echo "$2" | tr '[:lower:]' '[:upper:]')"
local score="$3"
local logfile=${4:-$OUTPUTFILE}
case "$result" in
'PASS' | 'PASSED' | 'PASSING') result='PASS'; ;;
'FAIL' | 'FAILED' | 'FAILING') result='FAIL'; ;;
'WARN' | 'WARNED' | 'WARNING') result='WARN'; ;;
*)
rlLogWarning "rlReport: Only PASS/WARN/FAIL results are possible."
result='WARN'
;;
esac
rlLogDebug "rlReport: result: $result, score: $score, log: $logfile"
if [ -z "$BEAKERLIB_COMMAND_REPORT_RESULT" ]; then
local BEAKERLIB_COMMAND_REPORT_RESULT="$__INTERNAL_DEFAULT_REPORT_RESULT"
fi
# report the result only if TESTID is set
if [ -n "$TESTID" ] ; then
$BEAKERLIB_COMMAND_REPORT_RESULT "$testname" "$result" "$logfile" "$score" \
|| rlLogError "rlReport: Failed to report the result"
fi
}
__INTERNAL_version_cmp() {
if [[ "$1" == "$2" ]]; then
return 0
fi
local i ver1="$1" ver2="$2" type="${3:--}"
ver1=($(echo "$ver1" | tr "$type" ' ')) ver2=($(echo "$ver2" | tr "$type" ' '))
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++)); do
if [[ -z "${ver2[i]}" ]]; then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
case $type in
-)
__INTERNAL_version_cmp "${ver1[i]}" "${ver2[i]}" _ || return $?
;;
_)
__INTERNAL_version_cmp "${ver1[i]}" "${ver2[i]}" . || return $?
;;
.)
if ((36#${ver1[i]} > 36#${ver2[i]})); then
return 1
fi
if ((36#${ver1[i]} < 36#${ver2[i]})); then
return 2
fi
;;
esac
done
return 0
}; # end of __INTERNAL_version_cmp
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlCmpVersion
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlCmpVersion
Compare two given versions composed by numbers and letters divided by dot (.),
underscore (_), or dash (-).
rlCmpVersion ver1 ver2
If ver1 = ver2, sign '=' is printed to stdout and 0 is returned.
If ver1 > ver2, sign '>' is printed to stdout and 1 is returned.
If ver1 < ver2, sign '<' is printed to stdout and 2 is returned.
=cut
rlCmpVersion() {
__INTERNAL_version_cmp "$1" "$2"
local res=$?
case $res in
0)
echo '='
;;
1)
echo '>'
;;
2)
echo '<'
;;
*)
echo "!"
esac
return $res
}; # end of rlCmpVersion
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlTestVersion
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlTestVersion
Test releation between two given versions based on given operator.
rlTestVersion ver1 op ver2
=over
=item op
Operator definitng the logical expression.
It can be '=', '==', '!=', '<', '<=', '=<', '>', '>=', or '=>'.
=back
Returns 0 if the expresison ver1 op ver2 is true; 1 if the expression is false
and 2 if something went wrong.
=cut
rlTestVersion() {
[[ " = == != < <= =< > >= => " =~ \ $2\ ]] || return 2
local res=$(rlCmpVersion $1 $3)
if [[ "$2" == "!=" ]]; then
if [[ "$res" == "=" ]]; then
return 1
else
return 0
fi
elif [[ "$2" =~ $res ]]; then
return 0
else
return 1
fi
}; # end of rlTestVersion
__INTERNAL_rlIsDistro(){
local distro="$(beakerlib-lsb_release -ds)"
local whole="$(beakerlib-lsb_release -rs)"
local major="$(beakerlib-lsb_release -rs | cut -d '.' -f 1)"
rlLogDebug "distro='$distro'"
rlLogDebug "major='$major'"
rlLogDebug "whole='$whole'"
echo $distro | grep -q "$1" || return 1
shift
[[ -z "$1" ]] && return 0
local arg sign res
for arg in "$@"
do
rlLogDebug "arg='$arg'"
# sanity check - version needs to consist of numbers/dots/<=>
[[ "$arg" =~ ^([\<\>\!]?=?)([0-9][0-9\.]*)$ ]] || {
rlLogError "unexpected argument format '$arg'"
return 1
}
sign="${BASH_REMATCH[1]}"
arg="${BASH_REMATCH[2]}"
rlLogDebug "sign='$sign'"
rlLogDebug "arg='$arg'"
if [[ -z "$sign" ]]; then
# shorten whole version so it matches arg in dots count
local whole_shorten="$(echo "$whole" | sed -r "s/([^.]+(\.[^.]+){$(echo "$arg" | grep -oF . | wc -w)}).*/\1/")"
rlLogDebug "whole_shorten='$whole_shorten'"
if [[ "$whole_shorten" == "$arg" ]]
then
return 0
fi
else
if [[ "$arg" =~ [.] ]]; then
rlLogDebug 'evaluation whole version (including minor)'
rlLogDebug "executing rlTestVersion \"$whole\" \"$sign\" \"$arg\""
rlTestVersion "$whole" "$sign" "$arg"
else
rlLogDebug 'evaluation major version part only'
rlLogDebug "executing rlTestVersion \"$major\" \"$sign\" \"$arg\""
rlTestVersion "$major" "$sign" "$arg"
fi
res=$?
rlLogDebug "result of rlTestVersion is '$res'"
return $res
fi
done
return 1
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlIsRHEL
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<=cut
=pod
=head2 Release Info
=head3 rlIsRHEL
Check whether we're running on RHEL.
With given number of version as parameter returns 0 if the particular
RHEL version is running. Multiple arguments can be passed separated
with space as well as any particular release (5.1 5.2 5.3).
Each version can have a prefix consisting of '<', '<=', '=', '>=', '>',
matching whenever the currently installed version is lesser, lesser or equal,
equal, equal or greater, greater than the version specified as argument.
Note that ie. '=5' (unlike just '5') matches exactly 5 (5.0),
not 5.N, where N > 0.
rlIsRHEL
Returns 0 if we are running on RHEL.
rlIsRHEL 4.8 5
Returns 0 if we are running RHEL 4.8 or any RHEL 5.
=cut
#'
rlIsRHEL(){
__INTERNAL_rlIsDistro "Red Hat Enterprise Linux" "$@" \
|| __INTERNAL_rlIsDistro "Red Hat Desktop release" "$@"
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlIsFedora
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<=cut
=pod
=head3 rlIsFedora
Check whether we're running on Fedora.
With given number of version as parameter returns 0 if the particular Fedora
version is running.
Range matching can be used in the form used by rlIsRHEL.
rlIsFedora
Returns 0 if we are running on Fedora.
rlIsFedora 9 10
Returns 0 if we are running Fedora 9 or 10.
=cut
#'
rlIsFedora(){
__INTERNAL_rlIsDistro "Fedora" "$@"
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlIsCentOS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<=cut
=pod
=head2 Release Info
=head3 rlIsCentOS
Check whether we're running on CentOS.
With given number of version as parameter returns 0 if the particular
CentOS version is running. Multiple arguments can be passed separated
with space as well as any particular release (5.1 5.2 5.3).
Each version can have a prefix consisting of '<', '<=', '=', '>=', '>',
matching whenever the currently installed version is lesser, lesser or equal,
equal, equal or greater, greater than the version specified as argument.
Note that ie. '=5' (unlike just '5') matches exactly 5 (5.0),
not 5.N, where N > 0.
rlIsCentOS
Returns 0 if we are running on CentOS.
rlIsCentOS 7.1 6
Returns 0 if we are running CentOS 7.1 or any CentOS 6.
=cut
#'
rlIsCentOS(){
__INTERNAL_rlIsDistro "CentOS" "$@"
}
: <<'=cut'
=pod
=head1 AUTHORS
=over
=item *
Ondrej Hudlicky <ohudlick@redhat.com>
=item *
Petr Muller <pmuller@redhat.com>
=item *
Jan Hutar <jhutar@redhat.com>
=item *
Petr Splichal <psplicha@redhat.com>
=item *
Ales Zelinka <azelinka@redhat.com>
=back
=cut