#!/bin/sh
#
#	$Id: ocf-tester,v 1.2 2006/08/14 09:38:20 andrew Exp $
#
# Copyright (c) 2006 Novell Inc, Andrew Beekhof
#                    All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#

LRMD=/usr/lib/heartbeat/lrmd
LRMADMIN=/usr/sbin/lrmadmin
METADATA_LINT="xmllint --noout --valid -"

num_errors=0

usage() {
    echo "ocf-tester [-Lh] -n resource_name [-o name=value]* /full/path/to/resource"
	echo ""
	echo "-L: use lrmadmin/lrmd for tests"
    exit $1
}

assert() {
    rc=$1; shift
    target=$1; shift
    msg=$1; shift

    if [ $# = 0 ]; then
	exit_code=0
    else
	exit_code=$1; shift
    fi

    if [ $rc -ne $target ]; then
	num_errors=`expr $num_errors + 1`
	echo "* rc=$rc: $msg"
	if [ $exit_code != 0 ]; then
	    echo "Aborting tests"
	    exit $exit_code
	fi
    fi
}

done=0
ra_args=""
verbose=0
while test "$done" = "0"; do
    case "$1" in
	-n) OCF_RESOURCE_INSTANCE=$2; ra_args="$ra_args OCF_RESOURCE_INSTANCE=$2"; shift; shift;;
	-o) name=${2%%=*}; value=${2#*=}; 
		lrm_ra_args="$lrm_ra_args $2";
		ra_args="$ra_args OCF_RESKEY_$name=$value"; shift; shift;;
	-L) use_lrmd=1; shift;;
	-v) verbose=1; shift;;
	-?) usage 0;;
	-*) echo "unknown option: $1"; usage 1;;
	*) done=1;;
    esac
done

if [ "x" = "x$OCF_ROOT" ]; then
    if [ -d /usr/lib/ocf ]; then
	export OCF_ROOT=/usr/lib/ocf
    else
	echo "You must supply the location of OCF_ROOT (common location is /usr/lib/ocf)"
	usage 1
    fi
fi

if [ "x" = "x$OCF_RESOURCE_INSTANCE" ]; then
    echo "You must give your resource a name, set OCF_RESOURCE_INSTANCE"
    usage 1
fi

agent=$1
if [ ! -e $agent ]; then
    echo "You must provide the full path to your resource agent"
    usage 1
fi
stopped_rc=7
has_demote=1
has_promote=1

start_lrmd() {
	lrmd_timeout=0
	lrmd_interval=0
	lrmd_target_rc=EVERYTIME
	lrmd_started=""
	$LRMD -s 2>/dev/null
	rc=$?
	if [ $rc -eq 3 ]; then
		lrmd_started=1
		$LRMD &
		sleep 1
		$LRMD -s 2>/dev/null
	else
		return $rc
	fi
}
add_resource() {
	$LRMADMIN -A $OCF_RESOURCE_INSTANCE \
		ocf \
		`basename $agent` \
		$(basename `dirname $agent`) \
		$lrm_ra_args > /dev/null
}
del_resource() {
	$LRMADMIN -D $OCF_RESOURCE_INSTANCE
}
parse_lrmadmin_output() {
	awk '
BEGIN{ rc=1; }
/Waiting for lrmd to callback.../ { n=1; next; }
n==1 && /----------------operation--------------/ { n++; next; }
n==2 && /return code:/ { rc=$0; sub("return code: *","",rc); next }
n==2 && /---------------------------------------/ {
        n++;
        next;
}
END{
	if( n!=3 ) exit 1;
	else exit rc;
}
'
}
exec_resource() {
	op="$1"
	args="$2"
	$LRMADMIN -E $OCF_RESOURCE_INSTANCE \
		$op $lrmd_timeout $lrmd_interval \
		$lrmd_target_rc \
		$args | parse_lrmadmin_output
}

if [ "$use_lrmd" = 1 ]; then
	echo "Using lrmd/lrmadmin for all tests"
	start_lrmd || {
		echo "could not start lrmd"
		exit 1
	}
	trap '
		[ "$lrmd_started" = 1 ] && $LRMD -k
	' EXIT
	add_resource || {
		echo "failed to add resource to lrmd"
		exit 1
	}
fi

lrm_test_command() {
	action="$1"
	msg="$2"
	[ "$verbose" -eq 0 ] || echo "$msg"
	exec_resource $action "$lrm_ra_args"
}

test_permissions() {
    action=meta-data
    msg=${1:-"Testing permissions with uid nobody"}
    if [ $verbose -ne 0 ]; then
    	echo $msg
    fi
    su nobody -s /bin/sh $agent $action > /dev/null
}

test_metadata() {
    action=meta-data
    msg=${1:-"Testing: $action"}
    if [ $verbose -ne 0 ]; then
    	echo $msg
    fi
    bash $agent $action | (cd /usr/share/resource-agents && $METADATA_LINT)
    rc=$?
    #echo rc: $rc
    return $rc
}

test_command() {
    action=$1; shift
    msg=${1:-"Testing: $action"}
    if [ "$use_lrmd" = 1 ]; then
    	lrm_test_command $action "$msg"
    	return $?
    fi
    #echo Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $verbose -no Running: "export $ra_args; bash $agent $action 2>&1 $v