#!/usr/bin/env bash

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

#
# Set up environment and run a test executable or script.
#
# Output nothing if test passes, show the output if it fails and
# leave output in <test>.log for examination.  
#
# If qpidd.port exists and is not empty run test with QPID_PORT=`cat qpidd.port`
# 
# If $VALGRIND if is set run under valgrind. If there are valgrind
# erros show valgrind output, also leave it in <test>.valgrind for
# examination.
#

wrapper="Qpid Test Wrapper"
function usage {
  echo "Usage:"
  echo " --working-dir DIR"
  echo " --build-dir DIR"
  echo " --source-dir DIR"
  echo " --python       - run python script"
  echo " --boost-test   - run boost unit test"
  echo " --xml          - XML output from tests"
  echo " --start-broker - start/stop broker before/after test"
  echo " --broker-options - use these extra options when starting broker"
  echo " --help           - print this message"
  echo " --             - This is required to separate the wrapped command"
  echo "                  from the test parameters"
}

function illegal_option {
  echo "$wrapper: $1 is not an accepted option"
  usage >&2
}

function no_command {
  echo "$wrapper: No wrapped command specified"
  usage >&2
}

function ignored_argument {
  echo "Ignored argument: $1" >&2
}

working_dir='.'

while true; do
case "$1" in
    --)                                  shift; break ;;
    # Split up any parameters expressed as --blah=foo
    # and process them next time round the loop
    --*=*)            option=${1%%=*}; param=${1#*=}
                      shift;
                      set -- "$option" "$param" "$@"  ;;
    --working-dir)    working_dir=$2;    shift 2      ;;
    --build-dir)      build_dir=$2;      shift 2      ;;
    --source-dir)     source_dir=$2;     shift 2      ;;
    --python)         run_python=yes;    shift        ;;
    --boost-test)     boost_test=yes;    shift        ;;
    --xml)            xml_output=yes;    shift        ;;
    --start-broker)   start_broker=yes;  shift        ;;
    --broker-options) qpidd_extra_options=$2; shift 2 ;;
    --help)           usage;             exit 0;      ;;
    --*)              illegal_option "$1"; exit 1;    ;;
    '')               no_command;        exit 1;      ;;
    *)                ignored_argument "$1"; shift;   ;;
esac
done

program=$1
shift

logfilebase=$(pwd -P)/$(basename $program)
source $build_dir/src/tests/test_env.sh || (echo "Error: Couldn't read test_env.sh (build settings)" ; exit 1)
source $srcdir/vg_check

# Allow environment to dictate if we output xml test results
if [ -n "$QPID_XML_TEST_OUTPUT" ] ; then
  xml_output=yes
fi

# Use VALGRIND_OPTS="--gen-suppressions=all" to generated suppressions
VALGRIND_OPTS="$VALGRIND_OPTS
--leak-check=full
--demangle=yes
--suppressions=$srcdir/.valgrind.supp
--num-callers=25
"

# Set up environment for running a Qpid test
if [ -n "$start_broker" ] ; then
  qpidd_command="$QPIDD_EXEC --auth=no --no-module-dir --daemon --port=0 --interface 127.0.0.1 --log-to-file $logfilebase-qpidd.log $qpidd_extra_options"
  if [ -n "$VALGRIND" ] ; then
    if [ -n "$xml_output" ] ; then
      QPID_PORT=$($VALGRIND $VALGRIND_OPTS --xml=yes --xml-file=$logfilebase-qpidd-vg.xml -- $qpidd_command)
    else
      QPID_PORT=$($VALGRIND $VALGRIND_OPTS --log-file=$logfilebase-qpidd.vglog -- $qpidd_command)
    fi
  else
    QPID_PORT=$($qpidd_command)
  fi
elif [ -r qpidd.port ]; then
  QPID_PORT=$(cat qpidd.port)
fi
export QPID_PORT
QPID_LOG_TO_FILE="$logfilebase.log"
export QPID_LOG_TO_FILE

# Export variables from makefile.
export srcdir

if [ -n "$VALGRIND" ] ; then
  if [ -n "$xml_output" ] ; then
    valgrind_command="$VALGRIND $VALGRIND_OPTS --xml=yes --xml-file=$logfilebase-vg.xml --"
  else
    VG_LOG="$logfilebase.vglog"
    rm -f $VG_LOG*
    valgrind_command="$VALGRIND $VALGRIND_OPTS --log-file=$VG_LOG --"
  fi
fi

ERROR=0
if [ -n "$run_python" -a -n "$PYTHON" ] ; then
    (cd $working_dir; $PYTHON $program "$@") || ERROR=1
elif [ ! -x $program ] ; then
    echo "Cannot execute $program"
    ERROR=1
elif file $program | grep -q ELF; then
  if [ -n "$boost_test" ] ; then
    # Set boost unit test environment
    if [ -n "$xml_output" ] ; then
      export BOOST_TEST_SHOW_PROGRESS=no
      export BOOST_TEST_OUTPUT_FORMAT=XML
      export BOOST_TEST_LOG_LEVEL=test_suite
      export BOOST_TEST_REPORT_LEVEL=no
      (cd $working_dir; $valgrind_command  $program "$@") > $logfilebase-unittest.xml || ERROR=1
    else
      (cd $working_dir; $valgrind_command  $program "$@") || ERROR=1
    fi
  else
    # This is a real executable, valgrind it if required
    # Hide output unless there's an error.
    (cd $working_dir; $valgrind_command  $program "$@" 2>&1) || ERROR=1
  fi
  if [ -n "$VG_LOG" ] ; then
    vg_check $VG_LOG* || ERROR=1
  fi
else
    (cd $working_dir; $program "$@") || ERROR=1
fi

# Check log
if [ -r $QPID_LOG_TO_FILE ]; then
egrep 'warning\|error\|critical' $QPID_LOG_TO_FILE && {
    echo "WARNING: Suspicious log entries in $QPID_LOG_TO_FILE, above."
}
fi

if [ -n "$start_broker" ] ; then
  $QPIDD_EXEC --no-module-dir --quit || ERROR=1

  # Check qpidd.log.
  egrep 'warning\|error\|critical' $logfilebase-qpidd.log && {
    echo "WARNING: Suspicious broker log entries in qpidd.log, above."
  }

  # Check valgrind log.
  if [ -n "$VALGRIND" -a -z "$xml_output" ] ; then
    vg_check $logfilebase-qpidd.vglog || ERROR=1
  fi
fi
exit $ERROR
