#!/usr/bin/env bash
#
# Copyright (c) 2009, Regents of the University of Colorado.
#
# Written by Sebastian Kuzminsky, based on loopbacktest.sh by David Young
#
# documentation boilerplate
CONFIGFILES=" \
${CONFIGSROOT}/loopback-ltp/loopback.rc
"
echo "########################################"
echo
pwd | sed "s/\/.*\///" | xargs echo "NAME: "
echo
echo "PURPOSE: To send a bundle over LTP. Uses the valgrind debugging/profiling
    tool: http://valgrind.org/"
echo
echo "CONFIG: standard ltp loopback:"
echo
for N in $CONFIGFILES
do
    echo "$N:"
    cat $N
    echo "# EOF"
    echo
done
echo "OUTPUT: Various debugging messages associated with the valgrind tool.
    valgrind output files will follow the pattern:
    $PWD/out.valgrind..."
echo
echo "########################################"



# message sent over ion
IONMESSAGE="iontestmessage"
IONSENDFILE=./ionsendfile.txt
IONRECEIVEFILE=./ionreceivefile.txt

if ! which valgrind > /dev/null 2> /dev/null; then
    echo "valgrind not found, skipping test"
    exit 2
fi


# uncomment the second line here if you want valgrind to emit suppressions for you
GEN_SUPPRESSIONS=""
#GEN_SUPPRESSIONS="--gen-suppressions=all"

# clean up any old valgrind output files
rm -f out.valgrind.*

echo "Starting ION..."

cp $IONDIR/ionstart.awk $IONDIR/ionstart_valgrind.awk
export AWKSCRIPT="$IONDIR/ionstart_valgrind.awk"

# Set a trap to GUARANTEE the valgrind awk is wiped when this script exits,
# even if the test fails, errors out, or you hit Ctrl+C.
trap 'rm "$AWKSCRIPT"; echo "Cleaned up $AWKSCRIPT"; killm f' EXIT

# Apply the sed patch to inject libtool and valgrind
valgrind_str="valgrind_cmd = \"libtool --mode=execute valgrind \
--suppressions=valgrind.suppressions.ionstart \
--quiet \
--log-file=out.valgrind.\" programs[x] \".%p \
--num-callers=25 \
--tool=memcheck \
--trace-children=yes \
--leak-check=full \"; \
if (0 != system(valgrind_cmd programs[x] \" iontemprun\")) {"
sed "s|if (0 != system(programs\[x\] \" iontemprun\")) {|${valgrind_str}|" \
    "${AWKSCRIPT}" >"${AWKSCRIPT}.tmp" &&
    mv "${AWKSCRIPT}.tmp" "${AWKSCRIPT}" || {
    echo "Failed to inject libtool and valgrind into awk script" >&2
    exit 1
}

$IONDIR/ionstart -I $CONFIGFILES

# create the test message in a sent file
# the exclamation point signals the bundle sender to quit
echo $IONMESSAGE > $IONSENDFILE
echo "!" >> $IONSENDFILE

# give ION some time to start up
sleep 9

# receive the message and store it in a file via test bundle sink
echo "starting bpsink"

libtool --mode=execute                             \
    valgrind                                       \
    $GEN_SUPPRESSIONS                              \
    --quiet                                        \
    --log-file=out.valgrind.loopback.bpsink.%p     \
    --num-callers=25                               \
    --tool=memcheck                                \
    --trace-children=yes                           \
    --leak-check=full                              \
    $IONDIR/bpsink ipn:1.1 > $IONRECEIVEFILE &

BPSINKPID=$!

# give bpsink some time to start up
sleep 9


# send the message in the file via test bundle source
echo "Sending message..."
libtool --mode=execute                             \
    valgrind                                       \
    $GEN_SUPPRESSIONS                              \
    --quiet                                        \
    --log-file=out.valgrind.loopback.bpsource.%p   \
    --num-callers=25                               \
    --tool=memcheck                                \
    --trace-children=yes                           \
    --leak-check=full                              \
    $IONDIR/bpsource ipn:1.1 < $IONSENDFILE &

BPSOURCEPID=$!

# give ION time to send the message
sleep 15


# kill the sender in case it didn't end properly
echo "stopping bpsource"
kill -2 $BPSOURCEPID > /dev/null 2> /dev/null


# bpsink does not self-terminate, so send it SIGINT
echo "stopping bpsink"
kill -2 $BPSINKPID >/dev/null 2>&1
sleep 2
kill -9 ${BPSINKPID} >/dev/null 2>&1


# shut down ion processes
echo "Stopping ion..."
ionstop

echo ""
echo "During ION shutdown, the 'killm' script may complain about: *** Unknown error: process <process name> not killed...try rebooting"
echo "This is normal for this test. Valgrind process will be cleared."

sleep 10


# compare the sent message to the received one
if ! grep -q "$IONMESSAGE" "$IONRECEIVEFILE"; then
    echo "Oh noes, data corruption!"
    echo
    echo "Sent this:"
    echo "----------------------------------------------------------------------"
    cat $IONSENDFILE
    echo "----------------------------------------------------------------------"
    echo
    echo "Received this:"
    echo "----------------------------------------------------------------------"
    cat $IONRECEIVEFILE
    echo "----------------------------------------------------------------------"
    RETVAL=1
else
    echo "bundle transfer successful!"
    RETVAL=0
fi

#
# see if valgrind noticed any problems
#

# terminate valgrind processes

# Pattern to match the Valgrind processes
pattern="valgrind(\.bin)? --suppressions=valgrind.suppressions.ionstart"

# Use pgrep with full pattern matching to find PIDs of processes matching the pattern
pids=$(pgrep -f "$pattern")

# Check if any PIDs were found
if [ -z "$pids" ]; then
    echo "All Valgrind processes ended..."
else
    # If PIDs were found, loop through each PID and kill the process
    for pid in $pids; do
        echo "Killing process $pid..."
        kill -9 $pid
    done
fi

echo "Valgrind output:"
echo "----------------------------------------------------------------------"
for V in out.valgrind.*; do
    if [ $(cat $V | wc -l) -gt 0 ]; then
        echo $V
        cat $V
    else
        rm $V
    fi
done

exit $RETVAL
