#!/bin/bash

testdir=$(dirname "$0")

ICECAST_BASE_URL="http://localhost:8000/"
counter=1
MOUNT_LISTENER_AUTH="foo.ogg"
MOUNT_SOURCE_AUTH="test.ogg"

AUTH_MOUNT="foobar:hackmemore"
AUTH_SOURCE="source:hackme"
AUTH_ADMIN="admin:hackme"
AUTH_INVALID="somenonsense123:morenonsense321"

L_USER="foo"
L_PASS="bar"
L_AUTH="$L_USER:$L_PASS"

command -v ffmpeg >/dev/null 2>&1 || {
    echo "1..0 # skip because ffmpeg is required but not present."
    exit 0
}

echo "# Starting Icecast"
../src/icecast -c "$testdir/icecast.xml" 2> /dev/null &
ICECAST_PID=$!
sleep 5

echo "# Starting Source client on /$MOUNT_LISTENER_AUTH"
ffmpeg -loglevel panic -re -f lavfi -i "sine=frequency=1000" -content_type application/ogg "icecast://$AUTH_SOURCE@127.0.0.1:8000/$MOUNT_LISTENER_AUTH" &
SOURCE1_PID=$!

echo "# Starting Source client on /$MOUNT_SOURCE_AUTH"
ffmpeg -loglevel panic -re -f lavfi -i "sine=frequency=1000" -content_type application/ogg "icecast://$AUTH_MOUNT@127.0.0.1:8000/$MOUNT_SOURCE_AUTH" &
SOURCE2_PID=$!

function test_endpoint {
    echo "# CURL $2"
    if test "x$4" == "x"; then
        res=$(curl -m 5 -o /dev/null -D - "$ICECAST_BASE_URL$2" 2>/dev/null | head -n 1 | cut -d$' ' -f2- | tr -d '\r\n')
    else
        res=$(curl -m 5 -u "$4" -o /dev/null -D - "$ICECAST_BASE_URL$2" 2>/dev/null | head -n 1 | cut -d$' ' -f2- | tr -d '\r\n')
    fi
    if test "$(echo "$res" | cut -d$' ' -f1)" -eq "$3"; then
        echo "# OK [$res]"
        echo "ok $counter - $1"
    else
        echo " FAIL [$res] Expected: $3"
        echo "not ok $counter - $1"
    fi
    ((counter++))
}

function test_sourcing {
    echo "# CURL $2"
    if test "x$4" == "x"; then
        res=$(curl -X PUT -m 5 -d /dev/random -o /dev/null -D - "$ICECAST_BASE_URL$2" 2>/dev/null | head -n 1 | cut -d$' ' -f2- | tr -d '\r\n')
    else
        res=$(dd if=/dev/urandom bs=8 count=32 2>/dev/null | curl -X PUT -m 5 -H "Content-Type: application/octet-stream" --data-binary "@-" -v -u "$4" -o /dev/null -D - "$ICECAST_BASE_URL$2" 2>/dev/null | head -n 1 | cut -d$' ' -f2- | tr -d '\r\n')
    fi
    if test "$(echo "$res" | cut -d$' ' -f1)" -eq "$3"; then
        echo "# OK [$res]"
        echo "ok $counter - $1"
    else
        echo "# FAIL [$res] Expected: $3"
        echo "not ok $counter - $1"
    fi
    ((counter++))
}

function manual_test_res {
    if test $2 -eq 1; then
        echo "ok $counter - $1"
    else
        echo "not ok $counter - $1"
    fi
    ((counter++))
}

echo "#"
echo "# Testing admin/manageauth endpoint"
test_endpoint "manageauth-add-noauth"         "admin/manageauth?id=4&username=$L_USER&password=$L_PASS&action=add"     401
test_endpoint "manageauth-add-invalid-noauth" "admin/manageauth?id=99&username=$L_USER&password=$L_PASS&action=add"    401
test_endpoint "manageauth-add-invalid"        "admin/manageauth?id=99&username=$L_USER&password=$L_PASS&action=add"    404 "$AUTH_ADMIN"
test_endpoint "manageauth-add-valid"          "admin/manageauth?id=4&username=$L_USER&password=$L_PASS&action=add"     200 "$AUTH_ADMIN"

echo "#"
echo "# Testing admin/buildm3u endpoint"
test_endpoint "buildm3u-user"     "admin/buildm3u?username=$L_USER&password=$L_PASS&mount=%2F$MOUNT_LISTENER_AUTH"  200
test_endpoint "buildm3u-fakeuser" "admin/buildm3u?username=something&password=foo&mount=%2F$MOUNT_LISTENER_AUTH"    200

echo "#"
echo "# Testing admin/stats endpoint"
test_endpoint "stats-noauth"        "admin/stats"  401
test_endpoint "stats-sourceauth"    "admin/stats"  401 "$AUTH_SOURCE"
test_endpoint "stats-listenerauth"  "admin/stats"  401 "$L_AUTH"
test_endpoint "stats-adminauth"     "admin/stats"  200 "$AUTH_ADMIN"

echo "#"
echo "# Testing admin/listclients endpoint"
test_endpoint "listclients-noauth"             "admin/listclients"                                 401
test_endpoint "listclients-sourceauth"         "admin/listclients"                                 401 "$AUTH_SOURCE"
test_endpoint "listclients-listenerauth"       "admin/listclients"                                 401 "$L_AUTH"
test_endpoint "listclients-adminauth-invalid"  "admin/listclients"                                 400 "$AUTH_ADMIN"
test_endpoint "listclients-adminauth"          "admin/listclients?mount=%2F$MOUNT_LISTENER_AUTH"   200 "$AUTH_ADMIN"

echo "#"
echo "# Testing admin/moveclients endpoint"
test_endpoint "moveclients-noauth"              "admin/moveclients"                                 401
test_endpoint "moveclients-sourceauth"          "admin/moveclients"                                 401 "$AUTH_SOURCE"
test_endpoint "moveclients-listenerauth"        "admin/moveclients"                                 401 "$L_AUTH"
test_endpoint "moveclients-adminauth-invalid"   "admin/moveclients"                                 400 "$AUTH_ADMIN"
test_endpoint "moveclients-adminauth"           "admin/moveclients?mount=%2F$MOUNT_LISTENER_AUTH"   200 "$AUTH_ADMIN"

echo "#"
echo "# Testing admin/updatemetadata endpoint"
test_endpoint "updatemetadata-noauth"             "admin/updatemetadata"                                 401
test_endpoint "updatemetadata-sourceauth"         "admin/updatemetadata"                                 401 "$AUTH_SOURCE"
test_endpoint "updatemetadata-listenerauth"       "admin/updatemetadata"                                 401 "$L_AUTH"
test_endpoint "updatemetadata-adminauth-invalid"  "admin/updatemetadata"                                 400 "$AUTH_ADMIN"
test_endpoint "updatemetadata-adminauth"          "admin/updatemetadata?mount=%2F$MOUNT_LISTENER_AUTH"   200 "$AUTH_ADMIN"

echo "#"
echo "# Testing admin/metadata endpoint"
test_endpoint "metadata-noauth"             "admin/metadata"                                                                       401
test_endpoint "metadata-sourceauth"         "admin/metadata"                                                                       401 "$AUTH_SOURCE"
test_endpoint "metadata-listenerauth"       "admin/metadata"                                                                       401 "$L_AUTH"
test_endpoint "metadata-adminauth-invalid"  "admin/metadata"                                                                       400 "$AUTH_ADMIN"
test_endpoint "metadata-sourceauth-mnt"     "admin/metadata?mount=%2F$MOUNT_LISTENER_AUTH&mode=updinfo&charset=UTF-8&song=Test1"   200 "$AUTH_SOURCE"
test_endpoint "metadata-adminauth-mnt"      "admin/metadata?mount=%2F$MOUNT_LISTENER_AUTH&mode=updinfo&charset=UTF-8&song=Test2"   200 "$AUTH_ADMIN"
test_endpoint "metadata-sourceauth-mnt"     "admin/metadata?mount=%2F$MOUNT_SOURCE_AUTH&mode=updinfo&charset=UTF-8&song=Test1"     200 "$AUTH_SOURCE"
test_endpoint "metadata-adminauth-mnt"      "admin/metadata?mount=%2F$MOUNT_SOURCE_AUTH&mode=updinfo&charset=UTF-8&song=Test2"     200 "$AUTH_ADMIN"
test_endpoint "metadata-mountauth-mnt"      "admin/metadata?mount=%2F$MOUNT_SOURCE_AUTH&mode=updinfo&charset=UTF-8&song=Test3"     200 "$AUTH_MOUNT"

echo "#"
echo "# Testing admin/listmounts endpoint"
test_endpoint "listmounts-noauth"              "admin/listmounts"                                 401
test_endpoint "listmounts-sourceauth"          "admin/listmounts"                                 401 "$AUTH_SOURCE"
test_endpoint "listmounts-listenerauth"        "admin/listmounts"                                 401 "$L_AUTH"
test_endpoint "listmounts-adminauth"           "admin/listmounts"                                 200 "$AUTH_ADMIN"
test_endpoint "listmounts-adminauth-mount"     "admin/listmounts?mount=%2F$MOUNT_LISTENER_AUTH"   200 "$AUTH_ADMIN"

echo "#"
echo "# Testing mountpoint which requires auth"
test_endpoint "authmount-noauth"        "$MOUNT_LISTENER_AUTH"   401
test_endpoint "authmount-sourceauth"    "$MOUNT_LISTENER_AUTH"   401 "$AUTH_SOURCE"
test_endpoint "authmount-listenerauth"  "$MOUNT_LISTENER_AUTH"   200 "$L_AUTH"
test_endpoint "authmount-adminauth"     "$MOUNT_LISTENER_AUTH"   401 "$AUTH_ADMIN"
test_endpoint "authmount-invalidauth"   "$MOUNT_LISTENER_AUTH"   401 "$AUTH_INVALID"

echo "#"
echo "# Testing mountpoint which doesn't require auth"
test_endpoint "mount-noauth"        "$MOUNT_SOURCE_AUTH"   200
test_endpoint "mount-sourceauth"    "$MOUNT_SOURCE_AUTH"   200 "$AUTH_SOURCE"
test_endpoint "mount-listenerauth"  "$MOUNT_SOURCE_AUTH"   200 "$L_AUTH"
test_endpoint "mount-adminauth"     "$MOUNT_SOURCE_AUTH"   200 "$AUTH_ADMIN"
test_endpoint "mount-invalidauth"   "$MOUNT_SOURCE_AUTH"   200 "$AUTH_INVALID"

echo "#"
echo "# Testing admin/killsource endpoint"
test_endpoint "killsource-noauth"              "admin/killsource"                                 401
test_endpoint "killsource-sourceauth"          "admin/killsource"                                 401 "$AUTH_SOURCE"
test_endpoint "killsource-listenerauth"        "admin/killsource"                                 401 "$L_AUTH"
test_endpoint "killsource-adminauth-invalid"   "admin/killsource"                                 400 "$AUTH_ADMIN"
test_endpoint "killsource-adminauth"           "admin/killsource?mount=%2F$MOUNT_LISTENER_AUTH"   200 "$AUTH_ADMIN"

echo "#"
echo "# Testing on-connect handling with probing"

test_sourcing "on-connect-test-noauth"      "test-on-connect.ogg"  401
sleep 3

if [ -f "$testdir/on-connect-success" ]; then
    manual_test_res "on-connect-notrigger" 0
    echo "# FAIL: on-connect triggered, even though it should not!"
    rm "$testdir/on-connect-success" > /dev/null 2>&1
else
    manual_test_res "on-connect-notrigger" 1
fi

test_sourcing "on-connect-test-sourceauth"  "test-on-connect.ogg"  200 "$AUTH_SOURCE"
sleep 3

if [ -f "$testdir/on-connect-success" ]; then
    manual_test_res "on-connect-trigger" 1
    echo "# OK: on-connect triggered!"
    rm "$testdir/on-connect-success" > /dev/null 2>&1
else
    manual_test_res "on-connect-trigger" 0
    echo "# FAIL: on-connect not triggered!"
fi

echo "#"
echo "# All tests done, cleanup..."
echo "#"

rm "$testdir/myauth" > /dev/null 2>&1

if kill $SOURCE1_PID > /dev/null 2>&1; then
    echo "# Terminated SOURCE1"
fi
if kill $SOURCE2_PID > /dev/null 2>&1; then
    echo "# Terminated SOURCE2"
fi

if kill $ICECAST_PID > /dev/null 2>&1; then
    echo "# Terminated Icecast"
fi

echo "1..$(((counter-1)))" # Number of tests to be executed.
exit 0