#!/bin/sh
# script/example-app: build the image, and on it the example app in
# deploy/example-app, then run the app's container and check that the
# health check passes, that a request is served through smallwebwaf,
# that `sv stop` stops smallwebwaf in order, and that `docker stop`
# stops the container without having to kill it. The container and both
# images are removed however the script ends. Building the app needs
# network access, for nixpkgs' binary cache. script/check does not run
# this.
set -eu

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"

# Named after this run, so that runs in other clones on the same host
# never touch each other's.
NAME="$("$SCRIPT_DIR/projectname")-example-$$"
IMAGE="$NAME-base"
APP_IMAGE="$NAME-app"
CONTAINER="$NAME"

cleanup() {
    docker rm --force "$CONTAINER" >/dev/null 2>&1 || true
    docker rmi --force "$APP_IMAGE" "$IMAGE" >/dev/null 2>&1 || true
}

fail() {
    echo "example-app: $*; the container's output:" >&2
    docker logs "$CONTAINER" >&2 || true
    exit 1
}

# wait_for <what fails> <command>...: run the command every second until
# it succeeds, for at most a minute.
wait_for() {
    failure="$1"
    shift
    tries=0
    until "$@"; do
        tries=$((tries + 1))
        [ "$tries" -lt 60 ] || fail "$failure"
        sleep 1
    done
}

healthy() {
    status="$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER")"
    [ "$status" = healthy ]
}

# logged <text>: the container's output holds text.
logged() {
    docker logs "$CONTAINER" 2>&1 | grep -qF "$1"
}

main() {
    cd "$ROOT"
    trap cleanup EXIT
    trap 'exit 1' HUP INT TERM

    docker build --no-cache -t "$IMAGE" .
    docker build --no-cache --build-arg SMALLWEBWAF_IMAGE="$IMAGE" \
        -t "$APP_IMAGE" deploy/example-app

    docker run --detach --name "$CONTAINER" --publish 127.0.0.1::8080 \
        "$APP_IMAGE" >/dev/null
    wait_for "the health check did not pass" healthy
    echo "example-app: the health check passes"

    address="$(docker port "$CONTAINER" 8080/tcp)"
    page="$(curl --fail --silent --show-error --max-time 10 "http://$address/")" ||
        fail "no answer on port 8080"
    [ "$page" = "hello from the example app" ] || fail "port 8080 answered $page"
    wait_for "smallwebwaf logged no request it forwarded" logged '"action":"forward"'
    echo "example-app: smallwebwaf passes a request to the app and its answer back"

    docker exec "$CONTAINER" sv stop smallwebwaf >/dev/null ||
        fail "sv stop smallwebwaf failed"
    wait_for "smallwebwaf did not stop in order" logged '"msg":"stopped"'
    echo "example-app: sv stop stops smallwebwaf in order"

    docker stop "$CONTAINER" >/dev/null
    status="$(docker inspect --format '{{.State.ExitCode}}' "$CONTAINER")"
    [ "$status" = 0 ] || fail "docker stop left exit status $status"
    echo "example-app: docker stop stops the container in order"
}

main "$@"
