diff --git a/tools/Makefile.am b/tools/Makefile.am
index ab0e4f0c81..b6ab11ec01 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,91 +1,92 @@
 #
 # heartbeat: Linux-HA heartbeat code
 #
 # Copyright (C) 2001 Michael Moerz
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
 # 
 # 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 MAINTAINERCLEANFILES    = Makefile.in ccdv
 
 INCLUDES                = -I$(top_builddir)/include -I$(top_srcdir)/include \
   			  -I$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \
   			  -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl
 
 EXTRA_DIST		= ccdv.c attrd.h
 
 apigid			= @HA_APIGID@
 habindir		= @bindir@
 halibdir		= $(libdir)/@HB_PKG@
 gliblib			= @GLIBLIB@
 
 habin_PROGRAMS		= cl_status cl_respawn 
 sbin_PROGRAMS		= attrd_updater
-halib_SCRIPTS		= haresources2cib.py	
+halib_SCRIPTS		= haresources2cib.py
 halib_PROGRAMS		= attrd	pingd
+sbin_SCRIPTS		= ocf-tester
 
 ## SOURCES
 ccdv: 	$(top_srcdir)/tools/ccdv.c
 	gcc -o ccdv $(top_srcdir)/tools/ccdv.c
 
 cl_status_SOURCES	= cl_status.c
 # A little trick. Now ccdv can be auto-built but not auto-cleaned.
 cl_status_DEPENDENCIES  = ccdv
 cl_status_LDADD		= $(top_builddir)/lib/hbclient/libhbclient.la	\
 			  $(top_builddir)/lib/clplumbing/libplumb.la	\
 	  		  $(top_builddir)/lib/pils/libpils.la	\
 			  $(gliblib)					\
 			  $(top_builddir)/replace/libreplace.la
 
 cl_respawn_SOURCES	= cl_respawn.c
 cl_respawn_LDADD	= $(top_builddir)/lib/clplumbing/libplumb.la	\
 			  $(top_builddir)/lib/apphb/libapphb.la		\
 	  		  $(top_builddir)/lib/pils/libpils.la	\
 			  $(gliblib)					\
 			  $(top_builddir)/replace/libreplace.la
 
 
 attrd_SOURCES		= attrd.c
 attrd_CFLAGS		= -DHA_VARLIBDIR='"@HA_VARLIBDIR@"'
 attrd_LDADD		=  $(CRM_DEBUG_LIBS)				\
 		  $(top_builddir)/lib/clplumbing/libplumb.la		\
 		  $(top_builddir)/lib/crm/common/libcrmcommon.la	\
 		  $(top_builddir)/lib/hbclient/libhbclient.la		\
 		  $(top_builddir)/lib/crm/cib/libcib.la			\
 		  $(GLIBLIB)						\
 		  $(LIBRT)
 
 pingd_SOURCES		= pingd.c
 pingd_CFLAGS		= -DHA_VARLIBDIR='"@HA_VARLIBDIR@"'
 pingd_LDADD		=  $(CRM_DEBUG_LIBS)				\
 		  $(top_builddir)/lib/clplumbing/libplumb.la		\
 		  $(top_builddir)/lib/crm/common/libcrmcommon.la	\
 		  $(top_builddir)/lib/hbclient/libhbclient.la		\
 		  $(GLIBLIB)						\
 		  $(LIBRT)
 
 attrd_updater_SOURCES	= attrd_updater.c
 attrd_updater_CFLAGS	= -DHA_VARLIBDIR='"@HA_VARLIBDIR@"'
 attrd_updater_LDADD	=  $(CRM_DEBUG_LIBS)				\
 		  $(top_builddir)/lib/clplumbing/libplumb.la		\
 		  $(top_builddir)/lib/crm/common/libcrmcommon.la	\
 		  $(GLIBLIB)						\
 		  $(LIBRT)
 
 
 install-data-hook:    # install-exec-hook doesn't work (!)
 	-chgrp $(apigid) $(DESTDIR)/$(habindir)/cl_status
 	-chmod g+s,a-w $(DESTDIR)/$(habindir)/cl_status
 
 .PHONY: install-exec-hook
diff --git a/tools/ocf-tester b/tools/ocf-tester
new file mode 100644
index 0000000000..7f6c3690e2
--- /dev/null
+++ b/tools/ocf-tester
@@ -0,0 +1,205 @@
+#!/bin/bash
+#
+#	$Id: ocf-tester,v 1.1 2006/08/14 09:14:13 andrew Exp $
+#
+#	pingd OCF RA. Does nothing but wait a few seconds, can be
+#	configured to fail occassionally.
+#
+# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Br�e
+#                    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.
+#
+
+num_errors=0
+
+function usage() {
+    echo "ocf-tester [-h] [-r resource_name] [-o name=value]* /full/path/to/resource"
+    exit $1
+}
+
+function assert() {
+    rc=$1; shift
+    target=$1; shift
+    msg=$1; shift
+    exit_code=$1; shift
+    if [ $rc != $target ]; then
+	num_errors=`expr $num_errors + 1`
+	echo -e " * rc=$rc: $msg"
+	if [ ! -z $exit_code ]; then
+	    echo "Aborting tests"
+	    exit $exit_code
+	fi
+    fi
+}
+
+done=0
+ra_args=""
+while test "$done" = "0"; do
+    case "$1" in
+        -n) ra_args="$ra_args OCF_RESOURCE_INSTANCE=$2"; shift; shift;;
+        -o) name=${2%%=*}; value=${2##*=}; 
+	    ra_args="$ra_args OCF_RESKEY_$name=$value"; shift; shift;;
+	-?) usage 0;;
+	-*) echo "unknown option: $1"; usage 1;;
+	*) done=1;;
+    esac
+done
+
+agent=$1
+stopped_rc=7
+has_demote=1
+has_promote=1
+
+function test_command() {
+    action=$1; shift
+    msg="Testing: $action"
+    if [ "x$1" != x ]; then
+	msg="$1"
+    fi
+    #echo $msg
+    #echo Running: "export $ra_args; bash $agent $action 2>&1 > /dev/null"
+    export $ra_args; 
+    bash $agent $action >/dev/null 2>&1
+    rc=$?
+    #echo rc: $rc
+    return $rc
+}
+
+# Begin tests
+echo Beginning tests for $agent...
+
+test_command meta-data
+rc=$?
+if [ $rc = 3 ]; then
+    assert $rc 0 "Your agent does not support the meta-data action"
+else
+    assert $rc 0 "The meta-data action cannot fail and must return 0"
+fi
+
+test_command validate-all
+rc=$?
+if [ $rc = 3 ]; then
+    assert $rc 0 "Your agent does not support the validate-all action"
+else
+    assert $rc 0 "Validation failed.  Did you supply enough options with -o ?" 1
+fi
+
+test_command monitor "Checking current state"
+rc=$?
+if [ $rc = 3 ]; then
+    assert $rc 7 "Your agent does not support the monitor action" 1
+
+elif [ $rc = 1 ]; then
+    assert $rc 7 "Monitoring a stopped resources should return 0"
+    echo "Test updated to expect 1 for stopped resources for the remainder of this run"
+    stopped_rc=1
+
+elif [ $rc = 8 ]; then
+    test_command demote "Cleanup, demote"
+    assert $? 0 "Your agent was a master and could not be demoted" 1
+
+    test_command stop "Cleanup, stop"
+    assert $? 0 "Your agent was a master and could not be stopped" 1
+
+elif [ $rc != 7 ]; then
+    test_command stop
+    assert $? 0 "Your agent was active and could not be stopped" 1
+fi
+
+test_command monitor
+assert $rc $stopped_rc "Monitoring a stopped resource should return $stopped_rc"
+
+test_command start
+assert $? 0 "Start failed.  Did you supply enough options with -o ?" 1
+
+test_command monitor
+assert $rc 0 "Monitoring an active resource should return 0"
+
+test_command notify
+rc=$?
+if [ $rc = 3 ]; then
+    echo " * Your agent does not support the notify action (optional)"
+else
+    assert $? 0 "The notify action cannot fail and must return 0"
+fi
+
+test_command demote "Checking for demote action"
+if [ $? = 3 ]; then
+    has_demote=0
+    echo " * Your agent does not support the demote action (optional)"
+fi
+
+test_command promote "Checking for promote action"
+if [ $? = 3 ]; then
+    has_promote=0
+    echo " * Your agent does not support the promote action (optional)"
+fi
+
+if [ $has_promote = 1 -a $has_demote = 1 ]; then
+    test_command demote "Testing: demotion of started resource"
+    assert $? 0 "Demoting a start resource should not fail"
+
+    test_command promote
+    assert $? 0 "Promote failed"
+
+    test_command demote
+    assert $? 0 "Demote failed" 1
+
+    test_command demote "Testing: demotion of demoted resource"
+    assert $? 0 "Demoting a demoted resource should not fail"
+
+    test_command promote "Promoting resource"
+    assert $? 0 "Promote failed" 1
+
+    test_command promote "Testing: promotion of promoted resource"
+    assert $? 0 "Promoting a promoted resource should not fail"
+
+    test_command demote "Demoting resource"
+    assert $? 0 "Demote failed" 1
+
+elif [ $has_promote = 0 -a $has_demote = 0 ]; then
+    echo " * Your agent does not support master/slave (optional)"
+
+else
+    echo " * Your agent partially supports master/slave"
+    num_errors=`expr $num_errors + 1`
+fi
+
+test_command stop
+assert $? 0 "Stop failed" 1
+
+test_command start "Restarting resource..."
+assert $? 0 "Start failed" 1
+
+test_command start "Testing: starting a started resource"
+assert $? 0 "Starting a running resource is required to succeed"
+
+test_command stop "Stopping resource"
+assert $? 0 "Stop could not clean up after multiple starts" 1
+
+test_command stop "Testing: stopping a stoped resource"
+assert $? 0 "Stopping a stopped resource is required to succeed"
+
+if [ $num_errors != 0 ]; then
+    echo Tests failed: $agent failed $num_errors tests
+else 
+    echo $agent passed all tests
+fi