#!/bin/bash
##
## Fixed simple script that runs a bunch of client tests for
## open pegasus extended testing
##  There are no variables in this test, it just runs the various
## tests and maintains no knowledge of when they stop

## TODO
## - Add more tests.
## - More sophisticated way to output data from the clients called
##   in the test. Today everything just splashes on the screen
## - Catch client failures
## 
##

usage()
{
cat << EOF
Usage: $(basename $0) - Run a selected number of pegasus cim client
    commands in parallel against a running cim server. if the -t
    option is set, execute the set of clients repeatedly until
    the number of minutes defined for -t has passed.
    Thus you can run a 24 hour test with
        chosimpletest -t 1440

    The commands to be executed are fixed defined in the script
    $PEGASUS_ROOT must exist to run this command
    
    chosimpletest [OPTIONS]

    OPTIONS
    -r count   Number of times to repeat the the commands.
               This passes directly to the command repeat options.
	       Note that all commands do not take the same time so
	       not all of the clients will take the same time to
	       finish
    -p         pull only
    -v         Verbose display
    -s         Start server before starting client tests
    -t min(h,d) Terminate min minutes after starting the test
               If the last character is h or d, this represents
	       hours or days. (i.e 3d will run the test for 3 days)
    -V     Running server under valgrind.  Used to determine if server
           is running since process names is different .
           NOTE: This only works because we ignore the check on process running.
EOF
}
##########################################################
## Class and instance defining variables used in tests
## these are as defined in the Client/tests/pullop Makefile but
## are extracted to allow for repeated tests in this script

NStressCxx=test/testProvider
CStressCxx=TST_ResponseStressTestCxx
CXXASSOC_INST_ID="Test_CLITestProviderClass.Id=\"Mike\" -n test/TestProvider"
CMPIASSOCOBJ_INST_ID="CMPI_TEST_Person.name=\"Melvin\" -n test/TestProvider"

CIMCLIHOSTID="-l localhost"
HOSTID="-H localhost"

## Configuration variables
TEST_END_SEC=0
STOPTIME=0
REPEAT=3
STARTSERVER=0
PULLONLY=0
RUN_UNDER_VALGRIND=0
CIMSERVERNAME=cimserver
## Number of parallel clients to run in TestClient
TEST_CLIENT_PARALLEL_CLIENTS=10

###############################################################
##  Capture if user ctrl-cs out of program and report current status
##
EXIT_PGM=0
# run if user hits control-c
control_c()
{
  echo -en "\n*** will end  at end of this loop ***\n"
  EXIT_PGM=1
}
 
# trap keyboard interrupt (control-c)
trap control_c SIGINT

declare -i addTime

######################################################################
## Test to be sure PEGASUS_ROOT exists and get input parameters
##
if [ -z "$PEGASUS_ROOT" ]; then
   echo PEGASUS_ROOT not set. Terminating and end of this client loop
   exit 1
fi 

##if [[ $(basename $PWD) != "pegasus" ]]; then
##   echo Must be run from pegasus directory
##   exit 1
##fi

while getopts "hvt:r:ps" OPTION
do 
     case $OPTION in 
         h)  usage 
             exit 1 
             ;; 
         v)  VERBOSE=true
             ;;
	 s)  STARTSERVER=1
	     ;;
         t)  STOPTIME=$OPTARG
	     case "$STOPTIME" in

            *m ) STOPTIME=${STOPTIME%%"m"}
            ;;

            *h ) STOPTIME=${STOPTIME%%"h"}
            STOPTIME=$((STOPTIME*60))
            ;;

            *d ) STOPTIME=${STOPTIME%%"d"}
            STOPTIME=$((STOPTIME*1440))
            ;;

            *[0-9] )
            ;;

            * ) echo ERROR: Option -t $STOPTIME incorrect
            exit 1
           ;;
	     esac
             TEST_END_SEC=$(date +%s --date="now + $STOPTIME min")
             ;;
     V) RUN_UNDER_VALGRIND=1
        ;;
	 r) REPEAT=$OPTARG
	    ;;
         p) PULL_ONLY=1
             ;;
         ?) usage 
             exit 
             ;;
         *) usage 
             exit 
             ;;
     esac 
done

## use this for repeat count on short commands. More repetitions
## since the time to run the various clients varies widely
REPEATL=$((REPEAT*8))

## If verbose, display results of command line options
if [ -n $VERBOSE ]; then
   echo VERBOSE on
   echo REPEAT:  $REPEAT
   echo STOPTIME to run: $STOPTIME minutes
   echo STARTSERVER = $STARTSERVER
   echo PULL_ONLY = $PULL_ONLY
   if [ $STOPTIME -ne 0 ]; then
      echo Client test will end at $(date -d @$TEST_END_SEC)
   else
	echo test for one loop
   fi
fi

## get the server pid and test to see if it is running
CIMSERVER_PID=$(ps -C $CIMSERVERNAME -o pid|grep -v PID | sed 's/^ *//')
PROCFILE=/proc/$CIMSERVER_PID

if [ ! -e $PROCFILE ]; then
    ##  If specified, start the server
    if [ $STARTSERVER -eq 1 ]; then
       echo start CIM Server
       cimserver
       ## Just to be sure it is started and running, sleep
       sleep 3
    else
       echo cimserver not running and you did not spec start.
       if [[[ "$RUN_UNDER_VALGRIND" -ne "1" ]]; then
           echo Terminating since there is no server
           exit 1
       fi
    fi
else
    echo CIM Server already running
fi

## get cimserver pid if it exists.
CIMSERVER_PID=$(ps -C $CIMSERVERNAME -o pid|grep -v PID | sed 's/^ *//')

if [ -n $VERBOSE ]; then
    echo CIMSERVER_PID "\"$CIMSERVER_PID\""
fi

PROCFILE=/proc/$CIMSERVER_PID

#############################################################
## execute a loop of the tests.  If -t was not used
## execute once.

STARTTIME=$(date +%s)
COUNT=1

## turn on statistics gathering for the server.  Without this
## we get no statistics capture.
cimcli son

## Loop to execute the client commands defined below. Each loop
## runs all the client commands to completion.
LOOPCOUNT=0

while true
do
    LOOPSTARTTIME=$(date +"%s")
    let LOOPCOUNT++
      
    if [ ! -e $PROCFILE ]; then
        echo cimserver $PROCFILE not running. Terminate test on loop $LOOPCOUNT
	exit 1
    fi

    ## Collection of non-pull tests.  execute only if the -p flag not
    ## set. 
    if [[ $PULL_ONLY == 0 ]]; then
        ## This command typically takes a couple of minutes to execute
        ## so use basic REPEAT. 
        TestClient -t $TEST_CLIENT_PARALLEL_CLIENTS -r $REPEAT &

        ## execute number of client operations repeatedly
        cimcli en CIM_ManagedElement --r $REPEATL --sum &
        cimcli ei CIM_ManagedElement --r $REPEATL --sum &
        cimcli ni CIM_ManagedElement --r $REPEATL --sum &
        cimcli gc CIM_ManagedElement --r $REPEATL --sum &
        cimcli cci --r $REPEATL &
        cimcli ec -di --r $REPEATL --sum &
        cimcli ei $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
        cimcli ni $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &

        cimcli pr $CXXASSOC_INST_ID -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
        cimcli pa $CXXASSOC_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
        cimcli pan $CXXASSOC_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
        cimcli pa $CMPIASSOCOBJ_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    fi

    ###############################################################
    ##  Tests involving pull operations
    ##
    
    ## Execute the general tests for pull operations
    ## can only run this test once because it sets parameters in
    ## provider and uses the results. Thus, the size of the response
    ## from the provider will change over the test. This test takes
    ## minutes to execute so execute once in each cycle
    make -C $PEGASUS_ROOT/src/Pegasus/Client/tests/pullop poststarttests  CStressCxx=TST_ResponseStressTestCxx2 &

    ## pull operations direct. Use only cimcli here because we cannot
    ## trust the size of the return from the StressCxx provider since we are
    ## also executing one set of the pullop makefile which changes the
    ## the provider parameters.
    cimcli pei $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pni $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pei $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pni $CStressCxx -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pr $CXXASSOC_INST_ID -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pa $CXXASSOC_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pan $CXXASSOC_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &
    cimcli pa $CMPIASSOCOBJ_INST_ID  -n $NStressCxx --sum --t --r $REPEATL $CIMCLIHOSTID &

    ## pullop for several operations. This executes both pull
    ## and enumerates and compares results. This is just a subset
    ## since we also run the complete poststarttest for pullop
    pullop r $CXXASSOC_INST_ID -C $HOSTID -v 1  -r $REPEATL &
    pullop a $CXXASSOC_INST_ID -C $HOSTID -v 1 -r $REPEATL &
    pullop an $CXXASSOC_INST_ID -C $HOSTID -v 1 -r $REPEATL &
    pullop a $CMPIASSOCOBJ_INST_ID -M 1 -N 1 -C -T $HOSTID -v 1 -r $REPEATL &

    echo $(basename $0) wait for all clients to finish
    wait
    echo $(basename $0) All clients done

    if [[ $EXIT_PGM -ne 0 ]]; then
        echo Exit Client loop immediatly. User terminated pgm
        exit 1
    fi

    ## compute time in minutes since started
    CURTIME=$(date +%s)
    RUNTIME=$(($CURTIME-$STARTTIME))
    RUNTIME_MIN=$(($RUNTIME/60))
    COUNTER=0

    ## if the -t was set test to see if we want to shut down script
    if [[ $TEST_END_SEC -ne 0 ]]; then
        if [[ $TEST_END_SEC -lt $(date +%s) ]]; then
           echo Stopped at defined end time after running $RUNTIME_MIN minutes
           exit 0
	else
	   echo Start new client loop. Loop number $((COUNTER+=1)) after running $RUNTIME_MIN
        fi
    else
       echo Test executed for one loop and is terminating
    fi

    LOOPENDTIME=$(date +"%s")
    diff=$(($LOOPENDTIME-$LOOPSTARTTIME))
    LOOPTIME_MIN=$(($diff % 60))
    echo $(basename $0) running $RUNTIME_MIN minutes loop $LOOPCOUNT $LOOPTIME_MIN

done

echo ++++++ $(basename $0) completed. Ran for $RUNTIME_MIN minutes +++++++


