#!/usr/bin/env bash
trap 'killm f' EXIT
#

# adapted from status_rpts test
# Silas Springer
# May 15, 2023

# documentation boilerplate
CONFIGFILES=" \
./global.ionrc \
./2.ipn.ltp/amroc.ltprc \
./2.ipn.ltp/amroc.bprc \
./2.ipn.ltp/amroc.ionconfig \
./2.ipn.ltp/global.ionrc \
./2.ipn.ltp/amroc.ionrc \
./2.ipn.ltp/amroc.ionsecrc \
./2.ipn.ltp/amroc.ipnrc \

"
CONFIGFILES=$CONFIGFILES"
./5.ipn.ltp/amroc.ltprc \
./5.ipn.ltp/amroc.bprc \
./5.ipn.ltp/amroc.ionconfig \
./5.ipn.ltp/global.ionrc \
./5.ipn.ltp/amroc.ionrc \
./5.ipn.ltp/amroc.ionsecrc \
./5.ipn.ltp/amroc.ipnrc \
"

CONFIGFILES=$CONFIGFILES"
./3.ipn.ltp/amroc.ltprc \
./3.ipn.ltp/amroc.bprc \
./3.ipn.ltp/amroc.ionconfig \
./3.ipn.ltp/global.ionrc \
./3.ipn.ltp/amroc.ionrc \
./3.ipn.ltp/amroc.ionsecrc \
./3.ipn.ltp/amroc.ipnrc \
"

echo "########################################"
echo
pwd | sed "s/\/.*\///" | xargs echo "NAME: "
echo
echo "PURPOSE: To determine if bptrace correctly initiates a bundle with status"
echo "reports enabled, and correctly listens for said reports. Also tests"
echo "bpsendfile with report-to EID and status report flags (Test 4)."
echo
echo "CONFIG: 3 node custom configuration:"
echo
for N in $CONFIGFILES
do
    echo "$N:"
    cat $N
    echo "# EOF"
    echo
done
echo "OUTPUT: Various status messages are expected to be found in
    ./2.ipn.ltp/ion.log"
echo
echo "########################################"

echo "Cleaning up old ION..."
rm -f 2.ipn.ltp/ion.log 3.ipn.ltp/ion.log 5.ipn.ltp/ion.log
rm -f 5.ipn.ltp/testfile1
rm -f 5.ipn.ltp/testfile2
rm -f 5.ipn.ltp/testfile3
rm -f 5.ipn.ltp/testfile4
rm -f 5.ipn.ltp/testfile5
killm
sleep 1

echo "Starting ION..."
export ION_NODE_LIST_DIR=$PWD
rm -f ./ion_nodes

# Start nodes.
cd 2.ipn.ltp
ionadmin amroc.ionrc
cd ../3.ipn.ltp
ionadmin amroc.ionrc
cd ../5.ipn.ltp
ionadmin amroc.ionrc

# NB: serialize the per-layer admin invocations across the 3 nodes.
# These were originally backgrounded (each followed by `&`), but on
# busy CI runners the resulting race let bpadmin start before its
# node's ltpadmin had finished registering the LTP induct/outduct.
# BP would then fail to come up ("BP agent is not started"), the
# subsequent system_up poll would time out at 30 s, and the test
# aborted before any of its actual assertions ran.  Total serial
# startup is only a few seconds; the parallelism wasn't load-bearing.

cd ../2.ipn.ltp
ionadmin global.ionrc
cd ../3.ipn.ltp
ionadmin global.ionrc
cd ../5.ipn.ltp
ionadmin global.ionrc

cd ../2.ipn.ltp
ionsecadmin amroc.ionsecrc
cd ../3.ipn.ltp
ionsecadmin amroc.ionsecrc
cd ../5.ipn.ltp
ionsecadmin amroc.ionsecrc

cd ../2.ipn.ltp
ltpadmin amroc.ltprc
cd ../3.ipn.ltp
ltpadmin amroc.ltprc
cd ../5.ipn.ltp
ltpadmin amroc.ltprc

cd ../2.ipn.ltp
bpadmin amroc.bprc
cd ../3.ipn.ltp
bpadmin amroc.bprc
cd ../5.ipn.ltp
bpadmin amroc.bprc

cd ../2.ipn.ltp
../../../system_up -i "p 30" -l "p 30" -b "p 30"

if [ $? -eq 3 ]
then
    echo ""
else
    echo "Node 2 not started: Aborting Test"
    exit 1
fi
cd ../3.ipn.ltp
../../../system_up -i "p 30" -l "p 30" -b "p 30"

if [ $? -eq 3 ]
then
    echo ""
else
    echo "Node 3 not started: Aborting Test"
    exit 1
fi
cd ../5.ipn.ltp
../../../system_up -i "p 30" -l "p 30" -b "p 30"

if [ $? -eq 3 ]
then
    echo ""
else
    echo "Node 5 not started: Aborting Test"
    exit 1
fi

sleep 1
bpsink ipn:5.1 &
BPSINK_PID=$!
cd ../2.ipn.ltp

# # let user work with nodes
# bash

# Snapshot src stats on node 2 before first trace
echo "=== Node 2 bpstats before trace 1 ==="
bpstats

# trace from node 2 to node 5 with all flags enabled
# Set rtt = ttl so bptrace waits long enough for the fwd report from node 2,
# which routes through the LTP self-loop and may arrive late. A 'del' report
# with 'TTL expired' may also arrive if the trace bundle expires at node 2.
OUTPUT=`bptrace -qos 0.1 -flags "fwd,rcv,dlv,del" -msg "test message 1" -ttl 20 -rtt 20 ipn:2.1 ipn:5.1 ipn:2.420`
echo "$OUTPUT"

# Snapshot src stats on node 2 after first trace
echo "=== Node 2 bpstats after trace 1 ==="
bpstats

# count the number of reports that had 'okay' status message, should have at
# least 4 (fwd@2, rcv@3, fwd@3, rcv+dlv@5). A 5th 'del' report with 'TTL
# expired' status may also appear; that is expected and not an error.
REPORT_OKAY=`echo "$OUTPUT" | grep 'okay' | wc -l `
if [ $REPORT_OKAY -ge 4 ];
then
    echo "OK: recieved all expected reports with 'okay' status ($REPORT_OKAY found)."
else
    echo "ERROR: unexpected number of 'okay' reports received: $REPORT_OKAY, expected >= 4."
    RETVAL=1
fi

# trace from node 2 to node 5 with only the delivery flag enabled
OUTPUT=`bptrace -qos 0.1 -flags dlv -msg "test message 2" -ttl 20 -rtt 20 ipn:2.1 ipn:5.1 ipn:2.420`
echo "$OUTPUT"
# count the number of reports that had 'okay' status message, should have 1
# dlv from node 5
REPORT_OKAY=`echo "$OUTPUT" | grep 'okay' | wc -l `
if [ $REPORT_OKAY -eq 1 ];
then
    echo "OK: recieved expected report with 'okay' status."
else
    echo "ERROR: unexpected number of reports recieved, expected one (1)."
    RETVAL=1
fi

# trace from node 2 to node 5 with only the delivery flag enabled
# trace node is admin endpoint, so we should only see messages in the logfile.
OUTPUT=`bptrace -qos 0.1 -flags dlv -msg "test message 3" -ttl 20 -rtt 20 ipn:2.1 ipn:5.1 ipn:2.0`
echo "$OUTPUT"
# count the number of reports that had 'okay' status message, should have 0
REPORT_OKAY=`echo "$OUTPUT" | grep 'okay' | wc -l `
# wait for contacts to temrinate (and give admin program time to put report into logfile)
sleep 7
if [ $REPORT_OKAY -eq 0 ];
then
    COUNT=`grep " \[s\] " ion.log | grep -E "status [8|9]" | wc -l`
    if [ $COUNT -eq 1 ];
    then
        echo "OK: found expected delivery report in log file."
    else
        echo "ERROR: No delivery report found in log file."
        RETVAL=1
    fi
else
    echo "ERROR: unexpected number of reports recieved, expected zero (0)."
    RETVAL=1
fi

# Test 4: bpsendfile with report-to EID and delivery status report flag
# Send a file from node 2 to node 5 with report-to ipn:2.420 and dlv flag.
# Use bptrace in listen mode to capture the delivery status report.
echo
echo "=== Test 4: bpsendfile with report-to EID and status report flags ==="
kill $BPSINK_PID 2>/dev/null
wait $BPSINK_PID 2>/dev/null
sleep 1
cd ../2.ipn.ltp

# Create a test file to send
echo "bpsendfile report-to test payload" > sendfile_test.txt

# Start bptrace in listen mode on the report-to endpoint
bptrace -listen -rtt 20 ipn:2.420 > bptrace_listen.txt 2>&1 &
LISTEN_PID=$!
sleep 1

# Start receiver on node 5 to accept the file
cd ../5.ipn.ltp
bprecvfile ipn:5.1 &
RECV_PID=$!
sleep 1
if ! kill -0 $RECV_PID 2>/dev/null; then
    echo "ERROR: bprecvfile failed to start on ipn:5.1 (endpoint may already be open)."
    kill $LISTEN_PID 2>/dev/null
    RETVAL=1
fi

# Send file with delivery report requested, report-to ipn:2.420
cd ../2.ipn.ltp
bpsendfile ipn:2.1 ipn:5.1 sendfile_test.txt 0.1 300 ipn:2.420 dlv
sleep 10

# Stop listener and receiver
kill $LISTEN_PID 2>/dev/null
kill $RECV_PID 2>/dev/null
sleep 1

echo "bptrace listen output:"
cat bptrace_listen.txt

# Check that we received a delivery report with 'okay' status
REPORT_DLV=$(grep 'dlv' bptrace_listen.txt | grep -c 'okay')
if [ "$REPORT_DLV" -ge 1 ];
then
    echo "OK: bpsendfile delivery report received with 'okay' status."
else
    echo "ERROR: No delivery report received for bpsendfile."
    RETVAL=1
fi

# Clean up test files
rm -f sendfile_test.txt bptrace_listen.txt
cd ../5.ipn.ltp
rm -f testfile1

# Shut down ION processes.
echo
echo "Stopping ION..."
#cd ../2.ipn.ltp
#./ionstop &
#cd ../3.ipn.ltp
#./ionstop &
#cd ../5.ipn.ltp
#./ionstop &

# Give all three nodes time to shut down, then clean up.
#sleep 3
echo "bptrace test completed."
exit $RETVAL
