#!/usr/bin/bash -efu

# Called from standard-test-basic role to run basic tests
# This script is copied to test-environment.

debug() {
    if [ -n "$DEBUG" ]; then
        echo "$*" >&2
    fi
}

msg_usage() {
    cat << EOF

Run basic test.

Usage:
$PROG <options>

Options:
-h, --help              display this help and exit
-v, --verbose           turn on debug
-w, --workdir           test environment work dir. Directory for test execution.
-a, --artifactsdir      test environment dir to store artifacts
-t, --testname          name of the test
    --timeout           test timeout
-c, --cmd               shell command to run the test
    --save-files        list of files to be saved to artifacts, files are separated by comma. Path is relative to workdir
EOF
}

# Entry

PROG="${PROG:-${0##*/}}"
DEBUG="${DEBUG:-}"
STR_CMD="${STR_CMD:-}"
STR_DEBUG="${STR_DEBUG:-}"
STR_VERBOSE="${STR_VERBOSE:-}"
STR_WORKDIR="${STR_WORKDIR:-}"
STR_TEST_NAME="${STR_TEST_NAME:-}"
STR_ARTIFACTS_DIR="${STR_ARTIFACTS_DIR:-/tmp}"
STR_TIMEOUT="${STR_TIMEOUT:-0}"
STR_SAVE_FILES="${STR_SAVE_FILES:-}"

# http://wiki.bash-hackers.org/howto/getopts_tutorial
opt=$(getopt -n "$0" --options "hvt:w:a:c:" --longoptions "help,verbose,cmd:,testname:,workdir:,artifactsdir:,timeout:,save-files:" -- "$@")
eval set -- "$opt"
while [[ $# -gt 0 ]]; do
    case "$1" in
        -t|--testname)
            STR_TEST_NAME="$2"
            shift 2
            ;;
        -c|--cmd)
            STR_CMD="$2"
            shift 2
            ;;
        -w|--workdir)
            STR_WORKDIR="$2"
            shift 2
            ;;
        -a|--artifactsdir)
            STR_ARTIFACTS_DIR="$2"
            shift 2
            ;;
        --timeout)
            STR_TIMEOUT="$2"
            shift 2
            ;;
        --save-files)
            STR_SAVE_FILES=$(echo "$2" | tr "," " ")
            shift 2
            ;;
        -v|--verbose)
            DEBUG="-v"
            shift
            ;;
        -h|--help)
            msg_usage
            exit 0
            ;;
        --)
            shift
            ;;
        *)
            msg_usage
            exit 1
    esac
done

# Entry

if [ -z "$STR_TEST_NAME" ] || [ -z "$STR_WORKDIR" ] || [ -z "$STR_CMD" ]; then
    echo "Use: $PROG -h for help."
    exit 0
fi

mkdir -p "$STR_WORKDIR"
mkdir -p "$STR_ARTIFACTS_DIR"
STR_WORKDIR="$(realpath "$STR_WORKDIR")"
STR_ARTIFACTS_DIR="$(realpath "$STR_ARTIFACTS_DIR")"
debug "Test: $STR_TEST_NAME"
debug "Command: $STR_CMD"
debug "Work dir: $STR_WORKDIR"
debug "Artifacts dir: $STR_ARTIFACTS_DIR"
debug "Timeout: $STR_TIMEOUT"

# Up to this point any fail is considered as ci-sytem fail. Exit code != 0.
# Starting from this point and bellow any fail is considered as a test fail. Exit code == 0.

clean_exit() {
    rc=$?;
    trap - SIGINT SIGTERM SIGABRT EXIT # clear the trap
    echo "Run test '$STR_TEST_NAME': done. Test's exit code: $rc"
    # Exit code == 0, no matter of the test result.
    # Close tee pipes
    for pid in $(ps -o pid --no-headers --ppid $$); do
        if [ -n "$(ps -p $pid -o pid=)" ]; then
            kill -s HUP $pid
        fi
    done
    local status="FAIL"
    # Return non-zero when test command not found
    if [[ $rc -eq 127 ]]; then
        echo "$STR_TEST_NAME (problem with test execution)" >&2
        status="ERROR"
    elif [[ $rc -eq 124 ]]; then
        # test case timed out
        echo "$STR_TEST_NAME (test aborted due to timeout)" >&2
        status="ERROR"
    elif [[ $rc -eq 0 ]]; then
        status="PASS"
    fi
    local run_journal="$STR_ARTIFACTS_DIR/test.log"
    echo "${status} $STR_TEST_NAME" >> "$run_journal"
    # Handle results.yml file, rename logs
    local results="$STR_ARTIFACTS_DIR/results.yml"
    local result=$(echo $status | tr '[:upper:]' '[:lower:]')
    test -f "$results" || echo 'results:' > "$results"
    printf '%s\n' '' \
        "- test: $STR_TEST_NAME" \
        "  result: $result"      \
        "  logs:"  \
        >> "$results"
    for log in "$logfile"; do
        if [ -f "$log" ]; then
            local prefixed_log="$STR_ARTIFACTS_DIR/${status}-$(basename $log)"
            mv -f "$log" "$prefixed_log"
            echo "  - $(basename $prefixed_log)" >> "$results"
        fi
    done
    for file in $STR_SAVE_FILES; do
        if [[ ! -d $STR_ARTIFACTS_DIR/$STR_TEST_NAME ]]; then
            mkdir -p $STR_ARTIFACTS_DIR/$STR_TEST_NAME
        fi
        set +f # allow expand wildcards on file name, like output*.log
        # if for some reason file doesn't exist, just ignore it
        cp -f $STR_WORKDIR/$file $STR_ARTIFACTS_DIR/$STR_TEST_NAME || true
        set -f
    done
    exit 0
}
trap clean_exit SIGINT SIGTERM SIGABRT EXIT

export PATH="$PATH:$STR_WORKDIR"
mkdir -p "$STR_ARTIFACTS_DIR"
# add str_ prefix to test logs
logfile="$STR_ARTIFACTS_DIR/$(echo "str_$STR_TEST_NAME" | sed -e 's/\//-/g').log"
logfile="$(realpath "$logfile")"
exec > >(tee -a "$logfile") 2>&1
cd "$STR_WORKDIR"
# Purpose to spawn new bash is to ignore -efu setting for current shell
# Test command: run-basic-test -w wodir -c 'false; echo 123; echo 333 >&2; touch "123 123"; exit 43' -t my_test -a logs -v
if [ -f "$STR_CMD" ]; then
    chmod 0775 "$STR_CMD"
fi
timeout --foreground "$STR_TIMEOUT" bash -c "$STR_CMD"
# Explicit return code
exit $?
