#!/bin/bash
set -o errexit -o nounset -o pipefail
function -h {
cat <<USAGE
 USAGE: test-suite <Mesos master URL>
        test-suite short <Mesos master URL>
        test-suite long <Mesos master URL>

  Run a suite of integration tests. By default, the short suite of tests is
  run.

USAGE
}; function --help { -h ;}                 # A nice way to handle -h and --help
export LC_ALL=en_US.UTF-8                    # A locale that works consistently

function main {
  [[ ! ${PTYHONPATH+isset} ]] || preamble >&2
  short "$@"
}

function globals {
  this="$(dirname "$0")"
}; globals

function preamble {
cat <<\EOF
You may need to set some environment variables to point to your Mesos build:

  # The distribute and proto eggs aren't strictly necessary.
  PYTHONPATH=/path/to/mesos/build/src/python/dist/mesos-*.egg

You probably won't need to set MESOS_NATIVE_LIBRARY.
EOF
}

function short {
  harness 60 short_tests "$@"
}

function long {
  harness 300 long_tests "$@"
}

function harness {
  local timeout="$1" ; shift
  ( cd "$this" && "$@" ) &
  local worker_process=$!
  trap "killtree $worker_process" TERM INT
  local token=/tmp/"$(printf deimos-test-suite.%04x.%04x $RANDOM $RANDOM)"
  ( trap 'exit 0' TERM
    sleep "$timeout"
    touch "$token"
    killtree "$worker_process" ) &>/dev/null &
  local term_process=$!
  trap "killtree $worker_process $term_process || true ; rm -f $token" TERM INT
  if wait "$worker_process"
  then
    msg "**** SUCCESS"
  else
    local code=$?
    [[ -e "$token" ]] && msg "**** TIMEOUT (${timeout}s)" || msg "**** FAILURE"
  fi
  killtree "$term_process" || true
  rm -f "$token"
  return "${code:-0}"
}

function test_ {
   local master="$1" test="$2" ; shift 2
  ./deimos-test.py --master "$master" --test "$test" "$@"
}

function test_sleep {
  test_ "$1" sleep    --test.trials "${3:-2}" --test.sleep "${2:-2}"
}

function test_executor {
  test_ "$1" executor --test.trials "${2:-2}"
}

function test_pg {
  test_ "$1" pg       --test.trials "${2:-2}"
}

function short_tests {
  test_sleep    "$1"
  test_pg       "$1"
  test_executor "$1"
}

function long_tests {
  short_tests   "$1"
  test_sleep    "$1" 10 10
  test_executor "$1" 5
}

function killtree {
  if [[ $# -gt 1 ]]
  then
    for arg in "$@"
    do killtree "$arg" || true
    done
    return 0
  fi
  kill -STOP "$1" &>/dev/null
  ps -e -o pid= -o ppid= | while read -r pid ppid
                           do
                             [[ $ppid = $1 ]] || continue
                             killtree "$pid"  || true
                           done
  kill -CONT "$1" &>/dev/null
  kill -TERM "$1" &>/dev/null
}

function msg { out "$*" >&2 ;}
function err { local x=$? ; msg "$*" ; return $(( $x == 0 ? 1 : $x )) ;}
function out { printf '%s\n' "$*" ;}

######################### Delegates to subcommands or runs main, as appropriate
if [[ ${1:-} ]] && declare -F | cut -d' ' -f3 | fgrep -qx -- "${1:-}"
then "$@"
else main "$@"
fi

