#!/bin/sh
# PCP QA Test No. 1290
# Basic pmproxy functionality
#
# valgrind version of qa/294
#
# Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
# Copyright (c) 2021 Ken McDonell.  All Rights Reserved.
#

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

# get standard environment, filters and checks
. ./common.product
. ./common.filter
. ./common.check

_check_valgrind
which pmdumptext >/dev/null 2>&1 || _notrun "No installed pmdumptext binary"

#debug# tmp=`pwd`/tmp
signal=$PCP_BINADM_DIR/pmsignal
status=1	# failure is the default!
username=`id -u -n`
$sudo rm -rf $tmp.* $seq.full
trap "_cleanup; rm -rf $tmp.*; exit \$status" 0 1 2 3 15

pmproxy_was_running=false
[ -f $PCP_RUN_DIR/pmproxy.pid ] && pmproxy_was_running=true
echo "pmproxy_was_running=$pmproxy_was_running" >>$here/$seq.full

rm -f $seq.out
case $PCP_PLATFORM
in
    darwin)
	ln $seq.out.darwin $seq.out || exit 1
	;;
    *)
	ln $seq.out.default $seq.out || exit 1
	;;
esac

_cleanup()
{
    echo "=== valgrind report ===" >>$here/$seq.full
    cat $tmp._valgrind >>$here/$seq.full
    if $pmproxy_was_running
    then
	echo "Restart pmproxy ..." >>$here/$seq.full
	_service pmproxy restart >>$here/$seq.full 2>&1
	_wait_for_pmproxy
    else
	echo "Stopping pmproxy ..." >>$here/$seq.full
	_service pmproxy stop >>$here/$seq.full 2>&1
    fi
}

_filter()
{
    sed \
	-e '/hinv/s/ [0-9][0-9]*$/ N/' \
	-e '/^[A-Z][a-z][a-z] [A-Z][a-z][a-z]  *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/{
# pmdumptext
s//DATE/
s/	[0-9][0-9.]*/	N/g
}' \
	-e '/^\[[A-Z][a-z][a-z] [A-Z][a-z][a-z]  *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9]]/{
# pmie trailer
s//[DATE]/
s/([0-9][0-9]*)/(PID)/
}' \
	-e '/expr_1/s/  *[0-9][0-9.]*/ N/g' \
	-e '/^@ [A-Z][a-z][a-z] [A-Z][a-z][a-z]  *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][[0-9][0-9][0-9]/{
# pmstat header1
s//@ DATE/
}' \
	-e '/^   1 min   swpd   free   buff  cache   pi   po   bi   bo   in   cs  us  sy  id/{
# pmstat header3
s//   1 min   swpd   free   buff  cache   si   so   bi   bo   in   cs  us  sy  id/
}' \
	-e '/[0-9?][0-9.Km]*  *[0-9?][0-9.Km]*  *[0-9?][0-9.Km]*  *[0-9?][0-9.Km]*  *[0-9?][0-9.Km]*/{
# pmstat data
s/  *?/ ?/g
s/  *[0-9][0-9.Km]*/ N/g
}' \
    | _filter_me
}

_filter_me()
{
    sed \
	-e "s/`hostname`/MY_HOSTNAME/g" \
	-e "s/`hostname | sed -e 's/\..*//'`/MY_HOSTNAME/" \
	-e "s/local:/MY_HOSTNAME/" \
	-e "s/localhost\.localdomain/MY_HOSTNAME/" \
	-e "s/localhost/MY_HOSTNAME/" \
	-e "s#$PCP_VAR_DIR#PCP_VAR_DIR#g" \
	-e "s#$PCP_SYSCONF_DIR/pmlogger/config.pmstat#TMP.logger.config#g" \
	-e "s,$tmp.config,TMP.logger.config,g" \
	-e "s#$tmp#TMP#g"
}

_filter_pmproxy()
{
    sed \
	-e '/^__pmSetSocketIPC: fd=/d' \
	-e '/^__pmSetDataIPC:/d' \
	-e '/^__pmDataIPC: /d' \
	-e '/^IPC table fd/d' \
	-e '/^pmproxy: disabled time series, requires libuv support (missing)/d' \
    # end

}

_do()
{
    echo
    echo "+++ $* +++" | tee -a $seq.full | _filter_me
    if which $1 >/dev/null 2>&1
    then
	eval $* 2>&1 | tee -a $seq.full | _filter
	connects=`grep AcceptNewClient $tmp.log | wc -l | sed -e 's/  *//g'`
	disconnects=`grep DeleteClient $tmp.log | wc -l | sed -e 's/  *//g'`
	difference=$(($connects - $disconnects))
	echo "N connects"
	echo "N-$difference disconnects"
    else
	echo "Skipped, no $1 binary installed"
    fi
}

_do_config()
{
    cat >$tmp.config <<End-of-File
log advisory on default {
    kernel.all.load
    swap.used
    mem.util.free
    mem.util.bufmem
    mem.bufmem
    mem.util.cached
    swap.in
    swap.pagesin
    swap.out
    swap.pagesout
    disk.all.blkread
    disk.all.blkwrite
    kernel.all.intr
    kernel.all.intr.non_vme
    kernel.all.pswitch
    kernel.all.cpu
}
End-of-File
}

$PCP_PS_PROG $PCP_PS_APP_FLAGS | grep -E '[P]ID|[p]mproxy' >>$here/$seq.full
_service pmproxy stop >/dev/null 2>&1
$sudo $signal -a pmproxy >/dev/null 2>&1
$PCP_PS_PROG $PCP_PS_APP_FLAGS | grep -E '[P]ID|[p]mproxy' >>$here/$seq.full

mkdir -p $tmp.rundir
export PCP_RUN_DIR=$tmp.rundir
proxyargs="-Dcontext -U $username"

__extra=''
if [ `id -un` = kenj ]
then
    # suppress the errors I've seen before so failure => new error(s)
    # this will be removed when the associated pmproxy issues have
    # been fixed
    #
    __extra="$__extra --suppressions=$tmp.suppress"
    cat <<'End-of-File' >$tmp.suppress
{
   110 bytes in 14 blocks are possibly lost in loss record 5 of 8
   Memcheck:Leak
   match-leak-kinds: possible
   fun:malloc
   fun:s_malloc
   fun:sdsnewlen
   fun:sdsnew
   fun:dict_handler
   fun:ini_parse_stream
   fun:ini_parse_file
   fun:ini_parse
   fun:pmIniFileParse
   fun:pmIniFileSetup
   fun:ParseOptions
   fun:main
}
{
   524 bytes in 14 blocks are possibly lost in loss record 8 of 8
   Memcheck:Leak
   match-leak-kinds: possible
   fun:realloc
   fun:s_realloc
   fun:sdsMakeRoomFor
   fun:sdscatfmt
   fun:dict_handler
   fun:ini_parse_stream
   fun:ini_parse_file
   fun:ini_parse
   fun:pmIniFileParse
   fun:pmIniFileSetup
   fun:ParseOptions
   fun:main
}

# at 0x4C6B36F: uv__stream_init (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C6C801: uv_tcp_init_ex (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x113B88: on_client_connection (server.c:497)
# by 0x4C6BAEE: uv__server_io (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Address 0x5686e28 is 552 bytes inside a block of size 800 free'd
# at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x1132F4: client_put (server.c:276)
# by 0x11310B: on_client_close (server.c:238)
# by 0x4C60868: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Block was alloc'd at
# at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x113AD2: on_client_connection (server.c:483)
# by 0x4C6BAEE: uv__server_io (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
{
   Invalid write of size 8 - added to GH #1203
   Memcheck:Addr8
   fun:uv__stream_init
   fun:uv_tcp_init_ex
   fun:on_client_connection
   fun:uv__server_io
   fun:uv__io_poll
   fun:uv_run
   fun:main_loop
   fun:main
}

# at 0x4C60848: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Address 0x5686e28 is 552 bytes inside a block of size 800 free'd
# at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x1132F4: client_put (server.c:276)
# by 0x11310B: on_client_close (server.c:238)
# by 0x4C60868: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Block was alloc'd at
# at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x113AD2: on_client_connection (server.c:483)
# by 0x4C6BAEE: uv__server_io (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
{
   Invalid write of size 8 - added to GH #1203
   Memcheck:Addr8
   fun:uv_run
   fun:main_loop
   fun:main
}

# at 0x4C71F7A: uv_fs_event_init (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x48BC1E4: pmDiscoverMonitor (discover.c:529)
# by 0x48BC4BA: created_callback (discover.c:638)
# by 0x48BB37B: pmDiscoverTraverse (discover.c:160)
# by 0x48BF00C: changed_callback (discover.c:1444)
# by 0x48BC0E5: fs_change_callBack (discover.c:495)
# by 0x4C71E4A: ??? (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Address 0x5559ac8 is 552 bytes inside a block of size 800 free'd
# at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x1132F4: client_put (server.c:276)
# by 0x11310B: on_client_close (server.c:238)
# by 0x4C60868: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Block was alloc'd at
# at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x113AD2: on_client_connection (server.c:483)
# by 0x4C6BAEE: uv__server_io (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
{
   Invalid write of size 8 - added to GH #1203
   Memcheck:Addr8
   fun:uv_fs_event_init
   fun:pmDiscoverMonitor
   fun:created_callback
   fun:pmDiscoverTraverse
   fun:changed_callback
   fun:fs_change_callBack
   obj:/usr/lib/x86_64-linux-gnu/libuv.so.1.0.0
   fun:uv__io_poll
   fun:uv_run
   fun:main_loop
   fun:main
}

# at 0x4C71F7A: uv_fs_event_init (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x48BC1E4: pmDiscoverMonitor (discover.c:529)
# by 0x48BF0CB: dir_callback (discover.c:1467)
# by 0x48BB37B: pmDiscoverTraverse (discover.c:160)
# by 0x48BF327: pmDiscoverRegister (discover.c:1527)
# by 0x489DFDB: pmDiscoverSetup (schema.c:1943)
# by 0x119905: on_redis_connected (redis.c:164)
# by 0x4897A95: redis_slots_finished (schema.c:84)
# by 0x48B3F51: seriesPassBaton (batons.c:143)
# by 0x4897B16: redis_slots_end_phase (schema.c:97)
# by 0x48B7DDA: redis_search_schema_callback (search.c:954)
# by 0x48ADA72: __redisRunCallBack (redis.c:1577)
# Address 0x559c3b8 is 552 bytes inside a block of size 800 free'd
# at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x1132F4: client_put (server.c:276)
# by 0x11310B: on_client_close (server.c:238)
# by 0x4C60868: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
# Block was alloc'd at
# at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
# by 0x113AD2: on_client_connection (server.c:483)
# by 0x4C6BAEE: uv__server_io (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C70ADF: uv__io_poll (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x4C607AB: uv_run (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
# by 0x114C14: main_loop (server.c:860)
# by 0x1121FE: main (pmproxy.c:451)
{
   Invalid write of size 8 - added to GH #1203
   Memcheck:Addr8
   fun:uv_fs_event_init
   fun:pmDiscoverMonitor
   fun:dir_callback
   fun:pmDiscoverTraverse
   fun:pmDiscoverRegister
   fun:pmDiscoverSetup
   fun:on_redis_connected
   fun:redis_slots_finished
   fun:seriesPassBaton
   fun:redis_slots_end_phase
   fun:redis_search_schema_callback
   fun:__redisRunCallBack
}

End-of-File
fi

# copied from _run_valgrind (which we cannot use here) ...
#
# extract version number I.J.K ... ignore anything after that,
# e.g. .SVN or .SVN-Debian for Debian-based distros
#
__version=`valgrind --version | sed -e 's/valgrind-//' -e 's/\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/'`
if [ -f $here/valgrind-suppress-$__version ]
then
    __extra="$__extra --suppressions=$here/valgrind-suppress-$__version"
    echo "Warning: using extra $__extra" >>$here/$seq.full
else
    echo "Warning: no extra suppressions found for valgrind version $__version" >>$here/$seq.full
fi
valgrind \
    --trace-children=yes \
    --leak-check=full --read-var-info=yes --gen-suppressions=all \
    --suppressions=$here/valgrind-suppress $__extra \
    --log-file=$tmp._valgrind \
	$PCP_BINADM_DIR/pmproxy $proxyargs -l $tmp.log \
	    2>$tmp._valgrind.err >$tmp._valgrind.out &

_wait_for_pmproxy
$PCP_BINADM_DIR/pmcd_wait -t 5sec -h localhost@localhost
$PCP_PS_PROG $PCP_PS_APP_FLAGS | grep -E '[P]ID|[p]mproxy' >>$here/$seq.full

# real QA test starts here
export PMPROXY_HOST=localhost
_do pminfo -h $PMPROXY_HOST -d pmcd.agent
_do pminfo -h $PMPROXY_HOST -f sample.hordes
_do pmprobe -v -h localhost hinv.ncpu
_do pmval -h `hostname` -t 0.5 -s 3 sample.bin

echo "kernel.all.load;" >$tmp.in
_do pmie -h $PMPROXY_HOST -c $tmp.in -v -t 0.5 -T 1.5 
echo "kernel.all.cpu.user :localhost;" >$tmp.in
_do pmie -h $PMPROXY_HOST -c $tmp.in -v -t 0.5 -T 1.5 
_do pmdumptext -h `hostname` -t 0.5 -s 2 sample.string.hullo
_do pmdumptext -t 0.5 -s 2 localhost:sample.string.hullo
_do pmdumptext -t 0.5 -s 2 `hostname`:kernel.all.load

# Note: there used to be special casing for Darwin/Solaris platforms
# here.  This is wrong, pmstat must still run on these platforms and
# produce no values for some columns.

_do pmstat -h $PMPROXY_HOST -t 0.5 -s 2
_do_config 
_do pmlogger -h localhost -c $tmp.config -t 0.5sec -s 3 -l $tmp.logger.log $tmp.arch
_do pmstat -S +0.25sec -t 0.5sec -a $tmp.arch -z

( echo ""; echo "=== pmproxy.log ===" ) >>$seq.full
cat $tmp.log >>$seq.full

# stop pmproxy and harvest output ...
#
$sudo $signal -a pmproxy >>$here/$seq.full 2>&1
sleep 2
$sudo $signal -a valgrind.bin >>$here/$seq.full 2>&1

# also copied from _run_valgrind (which we cannot use here) ...
#
echo
echo "=== pmproxy std out ==="
cat $tmp._valgrind.out
echo "=== pmproxy std err ==="
cat $tmp._valgrind.err
echo "=== filtered valgrind report ==="
cat $tmp._valgrind | _filter_valgrind | sed -e "s@$tmp@TMP@g"

# success, all done
status=0
exit
