#! /bin/sh
# PCP QA Test No. 578
# Test for Bug #660497, change openfds metric to be the
# largest known file descriptor used by pmcd.
# This means the file descriptor can only ever increase.
# The following behaviour is expected:
#	the file descriptor will increase when a client or pmda connects
# 	the file descriptor will stay the same when a client or pmda disconnects
#
# Copyright (c) 1995-2002 Silicon Graphics, Inc.  All Rights Reserved.
#

seq=`basename $0`
echo "QA output created by $seq"

# get standard filters
. ./common.product
. ./common.filter
. ./common.check

[ -d $PCP_PMDAS_DIR/simple ] || _notrun "simple PMDA directory is not installed"

status=1	# failure is the default!
trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15
rm -f $seq.full

signal=$PCP_BINADM_DIR/pmsignal
simple_domain=253
if [ -x pmobjstyle ]
then
    style=`pmobjstyle`
else
    style=''
fi

_start_client()
{
    pmval -T 10sec pmcd.client.whoami >$tmp.tmp 2>&1 &
    echo "=== Started client ===" | tee -a $here/$seq.full
    sleep 3
}

# Remove the PMDA and restore pmcd.conf
#
_cleanup()
{
    [ -f $PCP_PMDAS_DIR/simple/simple.conf.$seq ] && _restore_config $PCP_PMDAS_DIR/simple/simple.conf

    if [ -f $PCP_PMCDCONF_PATH.$seq ]
    then
	echo "=== Resetting pmcd.conf back to original state ==="
	_restore_config $PCP_PMCDCONF_PATH
        _restore_config $PCP_VAR_DIR/pmns/root
    	echo "=== Restart PMCD ==="
	unset PMCD_PORT
	_service pcp restart | _filter_pcp_start
	_wait_for_pmcd
	_wait_for_pmlogger
    fi
    
    if grep '^simple' $PCP_PMCDCONF_PATH >/dev/null
    then
	:
    else
	# simple was not installed, cull namespace
	#
	cd $PCP_PMDAS_DIR/simple
	$sudo ./Remove >/dev/null
    fi
    
    if [ -f $tmp.log ]
    then
	echo '=== pmcd log' >>$here/$seq.full
	cat $tmp.log >>$here/$seq.full
    fi

    rm -rf $tmp.*
}

trap "_cleanup; exit \$status" 0 1 2 3 15

_filter_ins()
{
    sed \
	-e 's/.* \(hash table entries\)/  NNN \1/' \
	-e 's/.* \(non-leaf nodes\)/  NNN \1/' \
	-e 's/.* \(leaf nodes\)/  NNN \1/' \
	-e 's/.* \(bytes of symbol table\)/  NNN \1/'
}

_filter_init()
{
    sed \
	-e "s/$$/PID/g"
}

_filter_openfds_value()
{
    $PCP_AWK_PROG '
BEGIN { fst_fds = "fst_fds"; sec_fds = "sec_fds"; thr_fds = "thr_fds"; step = 0 }
$1 == "pmcd.openfds"	{ want = 1; next }
NF == 0			{ want = 0; next }
want == 1 && $1 == "value" && step == 0 { 
	fst_fds = $2; step = 1; next }
want == 1 && $1 == "value" && step == 1 { 
	sec_fds = $2; step = 2; next }
want == 1 && $1 == "value" && step == 2 { 
	thr_fds = $2; 
	# Need some slop here (possibly because of non-determinism in
	# parallel checking in connection code), so
	# - after Install open fds to be within 0,+10
	# - after Remove open fds to be within 0,+4
	#
	if (fst_fds <= sec_fds && sec_fds <= fst_fds+10)
	    printf("=== Info: After Install, openfds has increased or stayed about the same as expected ===\n");
	else {
	    printf("=== Error: After Install, openfds has unexpectedly changed ===\n");
	    printf("\t previous value %d, current value %d (expect [%d..%d])\n", fst_fds, sec_fds, fst_fds, fst_fds+10);
	    }
	if (sec_fds <= thr_fds && thr_fds <= sec_fds+4)
	    printf("=== Info: After Remove, openfds has stayed about the same as expected ===\n");
	else {
	    printf("=== Error: After Remove, openfds has unexpectedly changed ===\n") 
	    printf("\t previous value %d, current value %d (expect [%d..%d]\n", sec_fds, thr_fds, sec_fds, sec_fds+4);
	    }
	next;
	}
	{ next } '
}

# no random clients, thanks
#
port=`_get_port tcp 6060 6070`
if [ -z "$port" ]
then
    echo "Arrggh ... no free TCP port in the range 6060 ... 6070"
    netstat -an
    exit
fi
PMCD_PORT=$port
export PMCD_PORT

# don't want these guys trying to connect to pmcd either ...
#
_service pmlogger stop >>$here/$seq.full 2>&1
_service pmie stop >>$here/$seq.full 2>&1
_service pmmgr stop >>$here/$seq.full 2>&1

# and we're starting a new pmcd ...
_service pmcd stop

# Build simple agent
#
echo "=== Building simple agent ===" | tee -a $here/$seq.full
unset ROOT TOOLROOT MAKEFLAGS
cd $PCP_PMDAS_DIR/simple

# get rid of warnings from simple if no config exists
[ -f simple.conf ] && _save_config simple.conf
echo "sec,min,hour" >$tmp.simple.conf
$sudo cp $tmp.simple.conf simple.conf

# Install the simple namespace, I don't bother to remove it again
#
$sudo ./Install -N < /dev/null | _filter_ins 2>&1
echo "Namespace installed"

if $sudo $PCP_MAKE_PROG > $tmp.make 2>&1
then
    echo "PMDA built"
else
    echo "Unable to build the simple PMDA:"
    cat $tmp.make
    exit
fi

sed -e "/^@ SIMPLE/s/SIMPLE/$simple_domain/" < help \
| $sudo $PCP_BINADM_DIR/newhelp -v 2 -o help
echo "Help generated"
cd $here

# Refresh PMCD
#
_renew_pmcd()
{
    echo "=== Restarting PMCD with minimal PMDAs ===" | tee -a $here/$seq.full
    if [ -f $tmp.newconf ]
    then
	$sudo cp $tmp.newconf $PCP_PMCDCONF_PATH
	$sudo $signal -a -s HUP pmcd
	sleep 4
	_wait_for_pmcd
    else
	echo caller - $1 - has not created $tmp.newconf !!!
    fi
}

# Install a standard pmda, but do not mess with the namespace
#
_agent_install()
{
    agent=$1
    domain=$2
    daemon=$3
    path=$PCP_PMDAS_DIR/$agent

    echo "=== Installing $agent ===" | tee -a $here/$seq.full
    cp $tmp.newconf $tmp.latest
    if $daemon
    then
	cat << End-of-File >> $tmp.latest
$agent	$domain	pipe	binary	$path/pmda$agent -d $domain
End-of-File
    else
    	cat << End-of-File >> $tmp.latest
$agent	$domain	dso	${agent}_init	$path/${style}pmda_$agent.$DSO_SUFFIX
End-of-File
    fi

    $sudo cp $tmp.latest $PCP_PMCDCONF_PATH

    $sudo $signal -a -s HUP pmcd
    sleep 4
    _wait_for_pmcd

    if _check_agent $agent true
    then
    	echo "$agent is alive and well"
    else
    	echo "Failed to install $agent"
	exit
    fi
}

# Remove a pmda
#
_agent_remove()
{
    agent=$1

    echo "=== Removing $agent ===" | tee -a $here/$seq.full
    _renew_pmcd _agent_remove

    if _check_agent $agent true
    then
    	echo "Failed to remove $agent"
	exit
    else
    	echo "$agent was removed"
    fi
}

# real QA test starts here

# Copy and replace pmcd.conf
#
_save_config $PCP_PMCDCONF_PATH
_save_config $PCP_VAR_DIR/pmns/root

if [ $PCP_PLATFORM = linux ] 
then
    cat << End-of-File > $tmp.newconf
# pmcd.conf generated by QA $seq
pmcd    2       dso     pmcd_init       $PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
linux   60      dso     linux_init      $PCP_PMDAS_DIR/linux/pmda_linux.so
End-of-File
elif [ $PCP_PLATFORM = darwin ]
then
    cat << End-of-File > $tmp.newconf
# pmcd.conf generated by QA $seq
pmcd    2       dso     pmcd_init       $PCP_PMDAS_DIR/pmcd/pmda_pmcd.dylib
darwin  78      dso     darwin_init     $PCP_PMDAS_DIR/darwin/pmda_darwin.dylib
End-of-File
elif [ $PCP_PLATFORM = solaris ]
then
    cat << End-of-File > $tmp.newconf
# pmcd.conf generated by QA $seq
pmcd	2	dso	pmcd_init	$PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
solaris	75	dso	solaris_init	$PCP_PMDAS_DIR/solaris/pmda_solaris.so
End-of-File
elif [ $PCP_PLATFORM = freebsd ]
then
    cat << End-of-File > $tmp.newconf
# pmcd.conf generated by QA $seq
freebsd	85	dso	freebsd_init	$PCP_PMDAS_DIR/freebsd/pmda_freebsd.so
pmcd	2	dso	pmcd_init	$PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
End-of-File
else
    echo "Arrgh ... need pmcd.conf output for $PCP_PLATFORM"
    exit 1
fi

#_renew_pmcd main

if [ -f $tmp.newconf ]
then
    $sudo cp $tmp.newconf $PCP_PMCDCONF_PATH
fi

# Start with a fresh pmcd log
#
# need to do this indirectly because system sudo cleanses the environment
#
echo "export PMCD_PORT=$PMCD_PORT" >$tmp.start
echo "$PCP_RC_DIR/pmcd start" >>$tmp.start
$sudo sh $tmp.start | _filter_pcp_start | _filter_init 2>&1
_wait_for_pmcd

_test_pmda()
{
    pmda_type=$1

    # Test PMDA 
    #
    echo
    echo "=== Testing PMDA as a $pmda_type ===" | tee -a $here/$seq.full

    rm -f $tmp.pminfo

    pminfo -f pmcd.openfds pmcd.client.whoami >$tmp.pminfo

    if [ "$pmda_type" != PIPE ]
    then
	_agent_install simple $simple_domain false
    else
	_agent_install simple $simple_domain true
    fi
    
    pminfo -f pmcd.openfds pmcd.client.whoami >>$tmp.pminfo
    
    _agent_remove simple
    pminfo -f pmcd.openfds pmcd.client.whoami >>$tmp.pminfo

    echo "=== pminfo output ===" >>$here/$seq.full
    cat $tmp.pminfo >>$here/$seq.full

    cat $tmp.pminfo | _filter_openfds_value

    echo "=== pmcd.log from _test_pmda ===" >>$here/$seq.full
    cat $PCP_LOG_DIR/pmcd/pmcd.log >>$here/$seq.full
}

_test_client()
{
    # Test a client
    #
    echo "=== Testing a Client ===" | tee -a $here/$seq.full

    rm -f $tmp.pminfo

    pminfo -f pmcd.openfds pmcd.client.whoami >$tmp.pminfo

    _start_client
    pminfo -f pmcd.openfds pmcd.client.whoami >>$tmp.pminfo

    wait
    pminfo -f pmcd.openfds pmcd.client.whoami >>$tmp.pminfo

    echo "=== pmval output ===" >>$here/$seq.full
    cat $tmp.tmp >>$here/$seq.full
    echo "=== pminfo output ===" >>$here/$seq.full
    cat $tmp.pminfo >>$here/$seq.full
    
    cat $tmp.pminfo | _filter_openfds_value

    echo "=== pmcd.log from _test_client ===" >>$here/$seq.full
    cat $PCP_LOG_DIR/pmcd/pmcd.log >>$here/$seq.full
}

_test_client
_test_pmda DSO
_test_pmda PIPE

status=0
# success, all done
exit

