#!/bin/sh
set -e

#run with
#autopkgtest ../runit-init_2.2.0-7_amd64.deb ../runit_2.2.0-7_amd64.deb ../getty-run_2.2.0-7_all.deb  . --test-name=trigger-sv -- qemu ../autopkgtest.img

rc=0
nrestart=0
testhome=/home/cpsvtestuser

rcadd() { printf '%s\n' "$*"; rc=$((rc+1)); }
fail() { rcadd "FAIL: $*"; }
warn() { printf '%s\n' "WARN: $*"; }

clean_sv() {
    rm -rf "/etc/service/.$1" || true
    rm -rf "/etc/service/$1"  || true
}

clean_usv () {
        rm -rf $testhome/.service/.$1 || true
        rm -rf $testhome/.service/$1 || true
}

fake_wtime() { # fake_wtime $svname [user]
    svname="$1"
    if [ -z "$2" ]; then
        #svname=installedfull-sv
        thissv=/etc/service/$svname
    else
        thissv=$testhome/.service/$svname
    fi
        wtnow=$(cat $thissv/.meta/wtime)
        wtfake=$((wtnow-1))
        echo "$wtfake" > $thissv/.meta/wtime
        wtact=$(cat $thissv/.meta/wtime)
    if [ $wtact -lt $wtnow ]; then
        return 0
    else
        return 1
    fi
}

goodsvs="installed-sv installedfull-sv linklog-sv multi-sv@default uninstalled-sv"
badsvs="norun-sv binempty-sv binnopath-sv nobin-sv"
#TODO user istances
usersvlist="user-sv@user linklog-usersv@user full-usersv@user"
dousertest=0


                                                                ###test setup###
echo "preparing test setup..."
#enable verbose/debug mode
touch /etc/runit/verbose
touch /etc/runit/debug
#echo "listing links inside /etc/service:"
#ls -l /etc/service/
cp -r debian/tests/sv/installed-sv /usr/share/runit/sv/
cp -r debian/tests/sv/uninstalled-sv /usr/share/runit/sv/
cp -r debian/tests/sv/installedfull-sv /usr/share/runit/sv/
rm -rf /usr/share/runit/sv/installedfull-sv/log #log is not needed here
echo 'no' > /usr/share/runit/sv/installedfull-sv/.meta/enable #set to: disabled by default
#setup for user services
cp -r debian/tests/sv/runsvdir@user /usr/share/runit/sv/
cp -a "/usr/share/runit/sv/installed-sv" "/usr/share/runit/sv/user-sv@user"
cp -r "debian/tests/sv/linklog-sv" "/usr/share/runit/sv/linklog-usersv@user"
cp -a "/usr/share/runit/sv/installedfull-sv" "/usr/share/runit/sv/full-usersv@user"
rm -rf /usr/share/runit/sv/full-usersv@user/log #log is not needed here
echo 'no' > /usr/share/runit/sv/full-usersv@user/.meta/enable #set to: disabled by default

#runsvchdir to default (trigger_sv enables there)
if [ ! -h /etc/service ]; then
   fail "setup: /etc/service is not a symlink" && exit "$rc"
else
    runsvchdir default
    servicelink=$(readlink -f /etc/service)
    if [ "$servicelink" != /etc/runit/runsvdir/default ]; then
        fail "setup: /etc/service is not a symlink"  && exit "$rc"
    fi
fi

#copy to runtime dir with cpsv a
CPSV_DEST=/usr/share/runit/sv.now CPSV_SOURCE=/usr/share/runit/sv.src  cpsv a installed-sv uninstalled-sv installedfull-sv
echo "...done"

if ! adduser  --comment "cpsv-tesuser" --disabled-password  cpsvtestuser; then
    fail "failed to create user: cpsvtestuser"
else
    if [ -d /home/cpsvtestuser ]; then
        #setup in home
        chpst -u cpsvtestuser mkdir -p /home/cpsvtestuser/.runit/sv
        chpst -u cpsvtestuser mkdir -p /home/cpsvtestuser/.runit/supervise
        chpst -u cpsvtestuser mkdir -p /home/cpsvtestuser/.runit/log
        chpst -u cpsvtestuser mkdir -p /home/cpsvtestuser/.runit/runsvdir/default
        chpst -u cpsvtestuser ln -s /home/cpsvtestuser/.runit/runsvdir/default     /home/cpsvtestuser/.runit/runsvdir/current
        chpst -u cpsvtestuser ln -s /home/cpsvtestuser/.runit/runsvdir/current   /home/cpsvtestuser/.service
        CPSV_DEST=/usr/share/runit/sv.now CPSV_SOURCE=/usr/share/runit/sv.src  cpsv -f s || true
        # create and enable the user intance
        cpsv p runsvdir@user runsvdir@cpsvtestuser
        ln -s  /etc/sv/runsvdir@cpsvtestuser  /etc/service/runsvdir@cpsvtestuser
        dousertest=1
        
    else
        fail "home dir: /home/cpsvtestuser not found"
    fi
fi


                                                ### test policy###
echo "testing policy: dot-links..."
sleep 1
# disable the service (create .link)
clean_sv "installed-sv"
ln -s  /usr/share/runit/sv.current/installed-sv  /etc/service/.installed-sv

#run trigger_sv manually, check that service is disabled
/lib/runit/trigger_sv setup
#/lib/runit/trigger_sv upgrade
[ -h /etc/service/installed-sv ] && fail "policy: installed-sv: expected disabled, but is enabled"
[ -h /etc/service/.installed-sv ] || fail "policy: installed-sv: missing .installed-sv symlink"

clean_sv "installed-sv"
echo "done"

                              ### core test: enabled/disabled bin logic###
echo "testing enable/disable core logic..."
sleep 1
# now that the .link is removed,  run the trigger again,
#  check that service is now enabled

/lib/runit/trigger_sv setup

#expected result:  installed-sv=enabled; uninstalled-sv=no links
[ ! -h /etc/service/installed-sv ] && fail "core: installed-sv: expected enabled, but it isn't"
[ -h /etc/service/.installed-sv ] && fail "core: installed-sv: expected enabled, but .installed-sv found"
[ -h /etc/service/uninstalled-sv ] && fail "core: uninstalled-sv: expected disabled, but it's enabled"
[ -h /etc/service/.uninstalled-sv ] && fail "core: uninstalled-sv: expected disabled (no links), but .uninstalled-sv found"
#test meta: enable=no on installedfull-sv
[ -h /etc/service/installedfull-sv ] && fail "core: installedfull-sv: expected disabled, but it's enabled"
[ -h /etc/service/.installedfull-sv ] && fail "core: installedfull-sv: expected disabled (no links), but .installedfull-sv found"

#emulate package removal, expected to be disabled
if [ -e /etc/service/installed-sv/.meta/bin ]; then
    echo "/bin/nonexistent" > /usr/share/runit/sv/installed-sv/.meta/bin
    echo "/bin/nonexistent" > /usr/share/runit/sv.current/installed-sv/.meta/bin
    #TODO fix cp_sv (cp -a) in cpsv --> make sure it overwrites/updates existing files in sv.current
else
    fail "core: installed-sv: bine metafile not found, can't test disable on binary removal"
fi
/lib/runit/trigger_sv setup
[ -h /etc/service/installed-sv ] && fail "core: installed-sv: expected disabled (pkg removed), but installed-sv found"
[ -h /etc/service/.installed-sv ] && fail "core: installed-sv: expected no links (pkg removed), but .installed-sv found"

clean_sv "installed-sv"
echo "done"


                               ### policy: /etc/sv overrides /usr/share/runit/sv.current###
echo "testing policy: /etc/sv/ override..."
sleep 1
# copy the service with meta unistalled to /etc/sv, the change bin to installed
cpsv a uninstalled-sv
[ -d /etc/sv/uninstalled-sv ] || fail "cpsv a: /etc/sv/uninstalled-sv: not found"
echo "/bin/true" > /etc/sv/uninstalled-sv/.meta/bin
/lib/runit/trigger_sv setup
#expected: is enabled, and that link points to /etc/sv
[ ! -h /etc/service/uninstalled-sv ] && fail "policy: uninstalled-sv: expected enabled, but it isn't"
[ -h /etc/service/.uninstalled-sv ] && fail "policy: uninstalled-sv: expected enabled, but .uninstalled-sv found"
uninstlink=$(readlink -f /etc/service/uninstalled-sv)
if [ "$uninstlink" != /etc/sv/uninstalled-sv ]; then
        fail "setup: /etc/service/uninstalled-sv does not point to /etc/sv/"
fi

clean_sv "uninstalled-sv"
clean_sv "installed-sv"

if [ -e /etc/sv/uninstalled-sv/supervise/lock ]; then
    echo "waiting for uninstalled-sv's runsv to exit.."
    chpst -l  /etc/sv/uninstalled-sv/supervise/lock true
    echo "..ok"
fi
rm -rf "/etc/sv/uninstalled-sv" || true
rm -rf "/usr/share/runit/sv.current/uninstalled-sv" || true
if [ -e /usr/share/runit/sv.current/installed-sv/supervise/lock ]; then
    echo "waiting for installed-sv's runsv to exit.."
    chpst -l  /usr/share/runit/sv.current/installed-sv/supervise/lock true
    echo "..ok"
fi
rm -rf "/usr/share/runit/sv.current/uninstalled-sv" || true
rm -rf "/usr/share/runit/sv.current/uninstalled-sv" || true

echo "...done"


                                                ### test upgrade restart-wtime###
if systemctl is-active --quiet runit.service ; then
    echo "testing upgrade/restart..."
    #test: onupgrade=restart
    echo 'yes' > /usr/share/runit/sv.current/installedfull-sv/.meta/enable
    echo 'yes' > /usr/share/runit/sv/installedfull-sv/.meta/enable #TODO fix in cpsv, see above
    /lib/runit/trigger_sv setup
    [ ! -h /etc/service/installedfull-sv ] && fail "upgrade-restart: uninstalled-sv: expected enabled, but it isn't"
    for i in 1 2 3 4 5 6 7; do #wait for the service to be up
        sleep 1 && echo "waiting for service to be up: $i"
        [ -p "/etc/service/installedfull-sv/supervise/ok" ] && break
    done
    sleep 1
    sv check installedfull-sv || fail "sv: not in the requested status"
    fake_wtime installedfull-sv
    sleep 1
    sv s installedfull-sv || true
    echo 0 > /etc/service/installedfull-sv/rcounter
    /lib/runit/trigger_sv upgrade
    sleep 2
    sv check installedfull-sv || fail "sv: after upgrade: not in the requested status"
    nrestart=$(cat /etc/service/installedfull-sv/rcounter)
    #expect 1(restart happened)
    [ $nrestart -eq '1' ] || fail "nrestart: expected 1 but value is $nrestart"
    echo "...done"
    #test: onupgrade=nostop
    echo "testing upgrade/nostop..."
    echo 0 > /etc/service/installedfull-sv/rcounter
    echo nostop > /etc/service/installedfull-sv/.meta/onupgrade
    fake_wtime installedfull-sv
    /lib/runit/trigger_sv upgrade
    sleep 2
    #expect 0(=norestart), wrong if 1(=restart)
    nrestart=$(cat /etc/service/installedfull-sv/rcounter)
    [ $nrestart -eq '0' ] || fail "nrestart: expected 0 but value is $nrestart"
    echo "...done"
else
    warn "can't perform upgrade/restart test, skipping..."
fi


                                                       ####user services test####

if [ "$dousertest" -eq 1 ]; then
    echo "user services: populating home with services..."
    #user-sv@user linklog-usersv@user full-usersv@user
    chpst -u cpsvtestuser cpsv -f s
    for usersv in user-sv linklog-usersv full-usersv ; do
        [ ! -d $testhome/.runit/sv/$usersv ] && fail "$usersv: directory not found in home - issue with cpsv"
    done
    #testhome=/home/cpsvtestuser
    #$testhome/.runit/sv
    #$testhome/.runit/supervise
    #$testhome/.runit/log
    #$testhome/.runit/runsvdir/default
    #$testhome/.service
    echo "done"
    
    ### test policy###
    echo "testing policy [user services]: dot-links..."
        clean_usv "user-sv"
        clean_usv "linklog-usersv"
        clean_usv "full-usersv"
    for usersv in user-sv linklog-usersv full-usersv ; do
        ln -s $testhome/.runit/sv/$usersv  $testhome/.service/.$usersv
    done
    chpst -u cpsvtestuser /lib/runit/trigger_sv setup
    for usersv in user-sv linklog-usersv full-usersv ; do
        [ -e $testhome/.service/$usersv ] && fail "$usersv: link found in $testhome/service/ but .link exist"
    done
        clean_usv "user-sv"
        clean_usv "linklog-usersv"
        clean_usv "full-usersv"
    echo "...done"

    ### core test: enabled/disabled bin logic###
    echo "testing enable/disable core logic [user services] ..."
    #NOTE full-usersv disabled by default //echo 'no' > /usr/share/runit/sv/full-usersv@user/.meta/enable
    chpst -u cpsvtestuser  /lib/runit/trigger_sv setup
    [ -h $testhome/.service/full-usersv ] && fail "full-usersv: link $testhome/.service/full-usersv  found but not expected"
    [ -e $testhome/.service/.full-usersv ] && fail "full-usersv: link $testhome/.service/.full-usersv found but not expected"
    for usersv in user-sv linklog-usersv  ; do
        [ ! -h $testhome/.service/$usersv ] && fail "$usersv: link $testhome/.service/$usersv not found but expected"
        [ -e $testhome/.service/.$usersv ] && fail "$usersv: link $testhome/.service/.$usersv found but not expected"
    done

    #emulate package removal, expected to be disabled
    if [ -e $testhome/.service/user-sv/.meta/bin ]; then
        echo "/bin/nonexistent" > /usr/share/runit/sv/user-sv@user/.meta/bin
        echo "/bin/nonexistent" > /usr/share/runit/sv.current/user-sv@user/.meta/bin
        #TODO fix cp_sv (cp -a) in cpsv --> make sure it overwrites/updates existing files in sv.current
    else
        fail "core: user-sv: bin metafile not found, can't test disable on binary removal"
    fi
    chpst -u cpsvtestuser  /lib/runit/trigger_sv setup
    [ -h $testhome/.service/user-sv ] && fail "core: user-sv: expected disabled (pkg removed), but user-sv found"
    [ -h $testhome/.service/.user-sv ] && fail "core: user-sv: expected disabled (pkg removed), but .user-sv found"
    echo "...done"

    ### test upgrade restart-wtime###
    if systemctl is-active --quiet runit.service ; then
        [ ! -h /etc/service/runsvdir@cpsvtestuser ] && fail "upgrade-restart: runsvdir@cpsvtestuser: expected enabled, but it isn't"
        for i in 1 2 3 4 5 6 7; do #wait for the service to be up
            sleep 1 && echo "waiting for service runsvdir@cpsvtestuser to be up: $i"
            [ -p "/etc/service/runsvdir@cpsvtestuser/supervise/ok" ] && break
        done
        sleep 1
        
        echo "testing upgrade/restart [user services] ..."
        #test: onupgrade=restart
        echo 'yes' > /usr/share/runit/sv.current/full-usersv@user/.meta/enable
        echo 'yes' > /usr/share/runit/sv/full-usersv@user/.meta/enable #TODO fix in cpsv, see above
        chpst -u cpsvtestuser  /lib/runit/trigger_sv setup
        [ ! -h $testhome/.service/full-usersv ] && fail "upgrade-restart: full-usersv: expected enabled, but it isn't"
        for i in 1 2 3 4 5 6 7; do #wait for the service to be up
            sleep 1 && echo "waiting for service full-usersv to be up: $i"
            [ -p "$testhome/.service/full-usersv/supervise/ok" ] && break
        done
        sleep 1
        chpst -u cpsvtestuser  sv check $testhome/.service/full-usersv || fail "sv: not in the requested status"
        fake_wtime full-usersv user
        sleep 1
        chpst -u cpsvtestuser sv s $testhome/.service/full-usersv || true
        chpst -u cpsvtestuser touch $testhome/.service/full-usersv/rcounter
#NOTE: if we don't touch the file here the test fails due to a permission problem because
# the finish file has no permission to write a root rcounter, and creating the file with
# 'chpst -u >' creates the file owned by root!
        chpst -u cpsvtestuser echo 0 > $testhome/.service/full-usersv/rcounter
#ls -l $testhome/.service/full-usersv/ | grep rcounter
#echo ""
        chpst -u cpsvtestuser /lib/runit/trigger_sv upgrade
        sleep 2
        chpst -u cpsvtestuser sv check $testhome/.service/full-usersv || fail "sv: after upgrade: not in the requested status"
        nrestart=$(cat $testhome/.service/full-usersv/rcounter)
        #expect 1(restart happened)
        [ $nrestart -eq '1' ] || fail "nrestart: expected 1 but value is $nrestart"
        echo "...done"
        
        #test: onupgrade=nostop
        echo "testing upgrade/nostop [user services] ..."
        chpst -u cpsvtestuser echo 0 > $testhome/.service/full-usersv/rcounter
#ls -l $testhome/.service/full-usersv/ | grep rcounter
#echo ""
        echo nostop > $testhome/.service/full-usersv/.meta/onupgrade
        fake_wtime full-usersv user
        chpst -u cpsvtestuser /lib/runit/trigger_sv upgrade
        sleep 2
        #expect 0(=norestart), wrong if 1(=restart)
        nrestart=$(cat $testhome/.service/full-usersv/rcounter)
        [ $nrestart -eq '0' ] || fail "nrestart: expected 0 but value is $nrestart"
        echo "...done"
    fi
fi


                                                            ###test cleanup###

#delete test services from /etc/sv, /usr/share/runit/sv.current | sv
#rm -rf ...
echo "test cleanup.."
runsvchdir svmanaged
rm -rf /etc/sv/installedfull-sv@instance1 || true
rm -rf /etc/sv/multi-sv@instance1 || true
rm -rf /etc/sv/uninstalled-sv
#rm -rf "$runtimedir/installedfull-sv@default" || true
for dir in installed-sv uninstalled-sv installedfull-sv; do
    rm -rf "/usr/share/runit/sv/$dir" || true
    rm -rf "/usr/share/runit/sv.current/$dir" || true
done
rm -f /etc/runit/verbose


[ "$rc" -eq 0 ] || echo "FATAL: failed test: trigger-sv rc is $rc"

exit "$rc"
