#!/bin/bash

set -e

ARGS=$@
PROG=$(basename $0)

IMAGE_ID=
LOOP=
LOCAL=1
TARGET_ENV=
TARGET_HOST=
TARGET_PORT=8080
NO_SSL_CHECK=
NO_CAPTURE=
GEN_TOKEN=

RUNPATH=

usage() {
    cat << EOF
USAGE: $0 [--debug] [--loop] [--env PYM_ENV|--image <image-id>|--host X --port Y] <tests_path>

Run acceptance tests against a local server, a local docker container or a
remote live server. If not arguments are provided, execute all test files under
the local directory 'testaccept/' against the host and port set in the
environment variables PYM_SERVER_HOST and PYM_SERVER_PORT.

OPTIONS:
  --image <image-id>  ID of a docker image to start and test against.
  --env <env>         Run tests against the live server defined in the pym config
                      file 'pym-config.<env>.yaml' (defaults to 'pym-config.yaml').
  --host <host>       Run tests against a specific IP address or hostname.
  --port <port>       Run tests against a specific TCP port.
  --loop              Run the tests in a loop, until failure.
  --no-ssl-check      Don't check SSL certificate.
  --gen-token         Generate a default JWT token to use in tests (won't by default).
  --nocapture         Show stdout from the test code.

USAGE:

  # Run all test files matching testaccept/test_v1_*
  # against api running at 127.0.0.1:8080
  export PYM_SERVER_HOST=127.0.0.1
  export PYM_SERVER_PORT=8080
  pymtest testaccept/test_v1_*

  # Run tests against the live api whose hostname
  # is specified in pym-config.yaml
  pymtest --env live testaccept/test_v1_*

  # Start the given pymacaron image in a local container and run
  # tests against it
  pymtest --image c7f755f84b68 testaccept/test_v1_*

  # Run tests against a given host and port
  pymtest --host api.foobar.com --port 443 testaccept/test_v1_*

EOF
}


parse_args() {
    while [ "$1" != "" ]; do
        case $1 in
            "--debug")        set -x;;
            "--env")          shift; export TARGET_ENV=$1;;
            "--live")         export TARGET_ENV='live';;
            "--staging")      export TARGET_ENV='staging';;
            "--image")        shift; IMAGE_ID=$1; export LOCAL=;;
            "--loop")         export LOOP=1;;
            "--host")         shift; export TARGET_HOST=$1;;
            "--port")         shift; export TARGET_PORT=$1;;
            "--gen-token")    export GEN_TOKEN=1;;
            "--no-ssl-check") export NO_SSL_CHECK=1;;
            "--nocapture")    export NO_CAPTURE=--nocapture;;
            "-h" | "--help")  usage; exit 0;;
            *)                export RUNPATH="$RUNPATH $1";;
        esac
        shift
    done
}

parse_args $ARGS

# Force re-generation of recent auth token
unset PYM_JWT_TOKEN

PYMCONFIG_ARGS=""
if [ ! -z "$TARGET_ENV" ]; then
    PYMCONFIG_ARGS="--env $TARGET_ENV"
fi

set_runpath() {
    if [ -z "$RUNPATH" ]; then
        RUNPATH="testaccept/"
        HERE=$PWD
        # Let's append all symlinked dirs's testaccept/ to RUNPATH
        for DIR in $(pymconfig $PYMCONFIG_ARGS --include-links)
        do
            cd $DIR
            ROOTDIR=$(git rev-parse --show-toplevel)
            if [ -d "$ROOTDIR/testaccept" ]; then
                echo "=> Appending tests from $ROOTDIR"
                RUNPATH="$RUNPATH $ROOTDIR/testaccept"
            fi
            cd $HERE
        done
        echo "=> Will execute tests $RUNPATH"
    fi
}

# Make sure we can connect to aws
if [ -z $AWS_SECRET_ACCESS_KEY ]; then
    SECRETS_FILE=~/.env.secrets
    if [ ! -e "$SECRETS_FILE" ]; then
        echo "ERROR: no secrets file at $SECRETS_FILE"
    else
        source $SECRETS_FILE
    fi
fi

if [ ! -z "$TARGET_HOST" ]; then
    echo "=> Running against $TARGET_HOST:$TARGET_PORT"
    export PYM_SERVER_HOST=$TARGET_HOST
    export PYM_SERVER_PORT=$TARGET_PORT
    export PYM_ENV=$TARGET_ENV

    set_runpath

elif [ ! -z "$IMAGE_ID" ]; then
    echo "=> Running against docker image $IMAGE_ID"

    export PYM_ENV=$TARGET_ENV
    if [ -z "$PYM_ENV" ]; then
        export PYM_ENV='dev'
    fi

    set_runpath

    # Start the container, passing all secrets as environment variables,
    # just like in the amazon EBS setup
    CMD="docker run"
    for VAR in $(pymconfig $PYMCONFIG_ARGS --env-secrets)
    do
        echo "=> Passing env variable $VAR"
        VALUE=$(env | grep "^$VAR=" | cut -d '=' -f 2-)
        if [ -z "$VALUE" ]; then
            echo "ERROR: variable $VAR has no value in env"
            exit 1
        fi
        CMD="$CMD -e $VAR='$VALUE'"
    done
    # Start the container on port 80 by default
    CMD="$CMD -e PORT=80 -e PYM_ENV=$PYM_ENV --rm -P $IMAGE_ID"

    echo "=> Starting container for image $IMAGE_ID"
    echo "EXEC [$CMD]"
    eval $CMD &
    RC=$?
    if [ $RC != 0 ]; then
        echo "ERROR: failed to start docker container"
        exit 1
    fi

    echo "=> Waiting for container to start"
    sleep 7

    CONTAINER_ID=$(docker ps | grep $IMAGE_ID | awk '{ print $1 }')

    if [ "$OS" == 'Darwin' ]; then
        PYM_SERVER_HOST=$(docker-machine ip default)

        # Make sure docker-machine's vm has a working dns resolver
        docker-machine ssh default "echo 'nameserver 8.8.8.8' > /etc/resolv.conf"

        PYM_SERVER_PORT=$(docker port $CONTAINER_ID | cut -d ':' -f 2)
    else
        PYM_SERVER_HOST=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${CONTAINER_ID})
        PYM_SERVER_PORT=80
    fi

    if [ -z "$PYM_SERVER_PORT" ]; then
        echo "ERROR: cannot find port exposed by container."
        echo "       did the container crash?"
        exit 1
    fi

elif [ ! -z "$TARGET_ENV" ]; then
    echo "=> Getting url of live host for $TARGET_ENV from pym-config"

    export PYM_SERVER_HOST=$(pymconfig $PYMCONFIG_ARGS --host)
    export PYM_SERVER_PORT=$(pymconfig $PYMCONFIG_ARGS --port)
    export PYM_ENV=$TARGET_ENV

    set_runpath

elif [ ! -z "$LOCAL" ]; then

    # TODO: check that server is indeed running locally. If not, start it?
    export PYM_SERVER_HOST=127.0.0.1
    export PYM_SERVER_PORT=8080

    # Let's try to guess if we should set PYM_ENV
    RUN_ENV=$(ps auxwwf | grep 'python server.py' | grep '\--env' | sed -e 's/.*--env //' | awk '{ print $1 }')
    if [ -z "$RUN_ENV" ]; then
        IS_RUNNING=$(ps auxwwf | grep 'python server.py' | grep '\--port')
        if [ -z "$IS_RUNNING" ]; then
            echo "ERROR: server is not started!"
            exit -1
        fi
        # The server is started without --env
        export PYM_ENV=dev
    else
        export PYM_ENV=$RUN_ENV
        export PYMCONFIG_ARGS="--env $RUN_ENV"
    fi

    set_runpath
fi

echo "=> Using PYM_ENV=$PYM_ENV"

if [ ! -z "$GEN_TOKEN" ]; then
    if [ -z "$PYM_JWT_TOKEN" ]; then
        echo "=> Getting an access token for the test user"
        export PYM_JWT_TOKEN=$(get_test_jwt_token | grep 'token:' | cut -d ':' -f 2)
        echo "=> Using token: $PYM_JWT_TOKEN"

        if [ -z "$PYM_JWT_TOKEN" ]; then
            echo "ERROR: failed to get an auth token for test user"
        fi
    fi
fi

echo "=> Running acceptance tests against $PYM_SERVER_HOST:$PYM_SERVER_PORT"
RC=0
if [ -z "$LOOP" ]; then
    nosetests -xv $NO_CAPTURE $RUNPATH || RC=$?
else
    while true; do
        nosetests -xv $NO_CAPTURE $RUNPATH || RC=$?
    done
fi

if [ ! -z "$CONTAINER_ID" ]; then
    echo "=> Stopping container $CONTAINER_ID"
    docker kill $CONTAINER_ID
fi

if [ "$RC" -ne 0 ]; then
    exit $RC
fi
