#!/usr/bin/env bash
trap 'killm f' EXIT
# AMS two-node demonstration and delivery smoke test.
#
# PURPOSE: demonstrate AMS publish/subscribe messaging carried across two
# separate continua over the RAMS/BP/TCP link (ramsgate), and confirm
# end-to-end delivery.  A moderate, fixed number of messages is published
# by amsbenchs (node 2) and counted by amsbenchr (node 3); delivery of the
# full set is verified.  This is a configuration demonstration and a
# delivery smoke test -- not a throughput measurement (loopback throughput
# is not representative of any real deployment).


# Benchtest variables-------------------------------------------------
COUNT=100
MESSAGE_SIZE=1000


# Shut down routine---------------------------------------------------
function stop_and_exit() {
    local retval=$1  # 0 for success, 1 for failure

    echo "Stopping ION..."

    # Call the shutdown script (redundant: in case ionstop or killm fails)
    "${ION_NODE_LIST_DIR}/shutdown_proc"

    # Use killm as a final, forceful cleanup for any remaining ION daemons.

    if [ "$retval" -eq 0 ]; then
        echo -e "AMS benchtest successfully completed."
        echo -e "SUCCESS SUCCESS SUCCESS SUCCESS SUCCESS SUCCESS SUCCESS SUCCESS\n"

        # The ION_NODE_LIST_DIR variable should point to the test's root directory.
        cat "${ION_NODE_LIST_DIR}/node3/bench.log"
    else
        echo -e "FAILURE FAILURE FAILURE FAILURE FAILURE FAILURE FAILURE FAILURE\n"
    fi
    echo ""
    exit $retval
}

# Process check -------------------------------------------------------
check_process_running() {
    local pid_to_check="${BENCHR_PID:-}"

    if [ -z "$pid_to_check" ]; then
        return 1 # NOT RUNNING: PID is unset.
    fi

    # Use 'kill -0' to check if the process is alive and not a zombie.
    # This is the most portable method and avoids parsing 'ps' output.
    # It returns 0 if the process exists, non-zero otherwise.
    if kill -0 "$pid_to_check" 2>/dev/null; then
        return 0 # STILL RUNNING
    else
        # The process is gone or is a zombie.
        # We can attempt a non-blocking wait to clean up a potential zombie.
        wait "$pid_to_check" 2>/dev/null
        return 1 # NOT RUNNING
    fi

    # CASE 2: The 'ps' command found the PID (it's a zombie).
    # The output of 'ps' can sometimes have whitespace, so we check if it CONTAINS 'Z'.
    if [[ "$process_state" == *"Z"* ]]; then
        # It's a zombie. Reap it to be a good citizen, then report it's not running.
        wait "$pid_to_check" 2>/dev/null
        return 1 # NOT RUNNING
    fi
}



# START TEST --------------------------------------------------------
# -------------------------------------------------------------------

# Cleanup prior to execution
./cleanup

export ION_NODE_LIST_DIR=$PWD

# Start nodes --------------------------------------------------------
cd node2
./ionstart
cd ../node3
./ionstart
sleep 2

echo -e "\nSTARTING AMS BENCH TEST--------------------------------- "
sleep 2

cd ../node3
echo -e "Starting amsbench receiver:"
amsbenchr > bench.log &
BENCHR_PID=$!
sleep 3

if ! check_process_running; then
    echo -e "Error: amsbenchr could not be started!"
    stop_and_exit 1
fi

# Let the receiver's subscription propagate across the RAMS/BP/TCP link to
# the publisher's continuum before publishing begins.  The sender's own
# 1-second snooze is too short for cross-continuum petition delivery; if the
# subscription arrives late the earliest (highest-numbered) messages are
# dropped and the delivered count falls short.  Settle here to close that
# race.
echo -e "Waiting for the subscription to propagate to the publisher..."
sleep 8

cd ../node2
echo -e "Starting amsbench sender:"
amsbenchs $COUNT $MESSAGE_SIZE 2>/dev/null &
sleep 3

# Wait for the receiver to finish or timeout -------------------------
TIMER=0
while check_process_running && [ "$TIMER" -lt 30 ]; do
    TIMER=$((TIMER + 1))
    sleep 1
    echo -e "Listening for published AMS messages..."
done

# If the timer exceeded 30 seconds, kill the process.
if check_process_running; then
    echo -e "Error: amsbenchr process hung or messages not delivered. Terminating..."
    kill $BENCHR_PID
    stop_and_exit 1
fi

# Verify delivery of messages ----------------------------------------
cd ../node3
echo "Reading bench.log for message delivery confirmation..."

# Wait up to 10 seconds for the log file to be flushed to disk.
verification_timer=0
while [ "$verification_timer" -lt 10 ]; do
    if grep -q "Received $COUNT messages" bench.log 2>/dev/null; then
        # Success message found, break the loop immediately.
        break
    fi
    sleep 1
    verification_timer=$((verification_timer + 1))
done


# Determine test results ---------------------------------------------
if grep -q "Received $COUNT messages" bench.log; then
    echo -e "\nSuccess: delivery of $COUNT messages verified."
    stop_and_exit 0
else
    echo -e "\nFailure: Log verification timed out. The final messages were not found in bench.log."
    echo "Dumping contents of bench.log for debugging:"
    cat bench.log
    stop_and_exit 1
fi
