#!/bin/bash

## Determine the absolute path to a directory or file
function abspath {
    if [[ -d "$1" ]]
    then
        pushd "$1" >/dev/null
        pwd
        popd >/dev/null
    elif [[ -e $1 ]]
    then
        pushd "$(dirname "$1")" >/dev/null
        echo "$(pwd)/$(basename "$1")"
        popd >/dev/null
    else
        echo "$1" does not exist! >&2
        return 127
    fi
}

function showHelp {
      echo "Usage: $0 [--out /path/to/output/dir] [--web /path/to/web/root] [--db mysql_database_name] [--db-args '-uuser -ppass dbname'] [--junit-xml /path/to/junit.xml] <file1.sql.bz2> <file2.sql.bz2> ..."
      echo
      echo "Note: To run all tests up-through version X, use @"
      echo "  - @4.4.0         (All snapshots predating 4.4.0)"
      echo "  - @4.2..4.7.0    (All snapshots from 4.2 to 4.7.0)"
      echo "  - @4.2..4.7.0:10 (As above, but returning a maximum of 10)"
      echo
      echo "(Note: Settings may be loaded from $SCRIPT_CFG)"
}

function usageError {
  echo
  echo "ERROR: $@"
  echo
  showHelp
  exit 2
}

## Drop all tables, views, etc
function drop_civicrm_sql {
  DBNAME="$TEST_DATABASE"

  echo; echo "Dropping civicrm_* views from database $DBNAME"
  echo "SELECT table_name FROM information_schema.TABLES  WHERE TABLE_SCHEMA='${DBNAME}' AND TABLE_TYPE = 'VIEW'" \
    | eval mysql $TEST_DATABASE_ARGS \
    | grep '^\(civicrm_\|log_civicrm_\)' \
    | awk -v NOFOREIGNCHECK='SET FOREIGN_KEY_CHECKS=0;' 'BEGIN {print NOFOREIGNCHECK}{print "drop view " $1 ";"}' \
    | eval mysql $TEST_DATABASE_ARGS

  echo; echo "Dropping civicrm_* tables from database $DBNAME"
  echo "SELECT table_name FROM information_schema.TABLES  WHERE TABLE_SCHEMA='${DBNAME}' AND TABLE_TYPE = 'BASE TABLE'" \
    | eval mysql $TEST_DATABASE_ARGS \
    | grep '^\(civicrm_\|log_civicrm_\)' \
    | awk -v NOFOREIGNCHECK='SET FOREIGN_KEY_CHECKS=0;' 'BEGIN {print NOFOREIGNCHECK}{print "drop table " $1 ";"}' \
    | eval mysql $TEST_DATABASE_ARGS
  ## This should also kill associated triggers

  echo; echo "Dropping civicrm_* functions from database $DBNAME"
  echo "SELECT SPECIFIC_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = '${DBNAME}' AND ROUTINE_TYPE = 'FUNCTION';" \
    | eval mysql $TEST_DATABASE_ARGS \
    | grep '^\(civicrm_\|log_civicrm_\)' \
    | awk -v NOFOREIGNCHECK='SET FOREIGN_KEY_CHECKS=0;' 'BEGIN {print NOFOREIGNCHECK}{print "drop function " $1 ";"}' \
    | eval mysql $TEST_DATABASE_ARGS
}

## usage: ERROR=$(check_error <console-output-file> <log-output-file>)
function check_error {
  OUTPUT="$1"
  LOG="$2"
  ## Checkout OUTPUT and LOG
  if grep '\[\(error\|warning\)\]' "$LOG" > /dev/null ; then
    echo 1
    return
  fi
  if tail -n1 "$OUTPUT" | grep '^Have a nice day' > /dev/null ; then
    echo
  else
    echo 1
  fi
}

#####################################################################
## Load options

SCRIPT_PATH=$(abspath "$0")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
PRJ_DIR=$(dirname "$SCRIPT_DIR")
SCRIPT_CFG="$PRJ_DIR/civicrm-upgrade-test.settings"
if [ -f "$SCRIPT_CFG" ]; then
  source $SCRIPT_CFG
fi

DATABASE_EXPRS=""
while [ -n "$1" ]; do
  case "$1" in
    --web)
      WEB_ROOT="$2"
      shift 2
      ;;
    --out)
      OUTPUT_DIR="$2"
      shift 2
      ;;
    --db)
      TEST_DATABASE="$2"
      shift 2
      ;;
    --db-args)
      TEST_DATABASE_ARGS="$2"
      shift 2
      ;;
    --junit-xml)
      JUNIT_XML="$2"
      shift 2
      ;;
    --help)
      showHelp
      exit 1
      ;;
    *)
       DATABASE_EXPRS="$DATABASE_EXPRS \"$1\""
      shift
      ;;
  esac
done

echo "Identify files: [$DATABASE_EXPRS]"
DATABASE_FILES=$(eval php "$SCRIPT_DIR/civicrm-upgrade-examples" $DATABASE_EXPRS)
if [ $? -ne 0 ]; then
  echo "Failed to evaluate expression \"$1\" => $DATABASE_FILES" >> /dev/stderr
  exit 1
fi
echo "$DATABASE_FILES"

#####################################################################
## Validate options
echo "Web Dir: [$WEB_ROOT]"
echo "Output Dir: [$OUTPUT_DIR]"
echo "Database Name: [$TEST_DATABASE]"

if [ ! -d "$WEB_ROOT" ]; then
  usageError "Missing or invalid web dir"
fi
if [ ! -d "$OUTPUT_DIR" ]; then
  #echo "Missing or invalid output dir"
  #exit 2
  if [ -z "$OUTPUT_DIR" ]; then
    usageError "Missing output dir"
  elif mkdir -p "$OUTPUT_DIR" ; then
    echo "Created output dir"
  else
    usageError "Failed to make output dir"
  fi
fi
if [ -z "$TEST_DATABASE" ]; then
  usageError "Missing or invalid database name"
fi
if [ -z "$TEST_DATABASE_ARGS" ]; then
  TEST_DATABASE_ARGS="$TEST_DATABASE"
fi
if [ -z "$DATABASE_FILES" ]; then
  usageError "Missing list of database backup files (*.sql.bz2)"
fi

#####################################################################
## Run upgrades

set -e
LOGPAT=$( cv --cwd="$WEB_ROOT" path -c 'configAndLogDir/CiviCRM.*.log' )
set +e

for SQLBZ2 in $DATABASE_FILES ; do
  NAME=$(basename $SQLBZ2)
  OUTPUT="${OUTPUT_DIR}/${NAME}.out"
  LOG="${OUTPUT_DIR}/${NAME}.log"

  echo ""
  echo "------------------------------------------------------"
  echo "Input [$SQLBZ2]"
  echo "Output [$OUTPUT] [$LOG]"

  drop_civicrm_sql
  echo; echo "Loading database $TEST_DATABASE"
  if [[ "$SQLBZ2" == *sql.bz2 ]]; then
    bzip2 -d -c "$SQLBZ2" | eval mysql $TEST_DATABASE_ARGS
  elif [[ "$SQLBZ2" == *sql.gz ]]; then
    gzip -d -c "$SQLBZ2" | eval mysql $TEST_DATABASE_ARGS
  elif [[ "$SQLBZ2" == *sql ]]; then
    eval mysql $TEST_DATABASE_ARGS < "$SQLBZ2"
  else
    echo "Unrecognized file extension [$SQLBZ2]"
    exit 2
  fi
  pushd "$WEB_ROOT" > /dev/null
  rm -f $LOGPAT
  echo; echo "Upgrading database $TEST_DATABASE"
  cv upgrade:db -vv --no-interaction > "$OUTPUT" 2>&1
  echo "LOGPAT: $LOGPAT" > $LOG
  cat $LOGPAT >> $LOG
  popd > /dev/null
  echo
done

#####################################################################
## Summary (Console)

echo "------------------------------------------------------"
echo "Summary"
for SQLBZ2 in $DATABASE_FILES ; do
  NAME=$(basename $SQLBZ2)
  OUTPUT="${OUTPUT_DIR}/${NAME}.out"
  LOG="${OUTPUT_DIR}/${NAME}.log"
  ERROR=$(check_error "$OUTPUT" "$LOG")

  if [ -z "$ERROR" ]; then
    echo "$NAME	OK"
  else
    echo "$NAME	ERROR"
  fi
done

#####################################################################
## Summary (JUnit)

if [ -n "$JUNIT_XML" ]; then
  echo "------------------------------------------------------"
  echo "Generate JUnit XML"
  COUNT=$(echo "$DATABASE_FILES" | wc -w)
  [ -f "$JUNIT_XML" ] && rm -f "$JUNIT_XML"
  touch "$JUNIT_XML"
  echo '<?xml version="1.0" encoding="UTF-8"?>' >> "$JUNIT_XML"
  echo '<testsuites>' >> "$JUNIT_XML"
  echo "<testsuite name=\"CivicrmUpgradeTest\" tests=\"$COUNT\">" >> "$JUNIT_XML"

  for SQLBZ2 in $DATABASE_FILES ; do
    NAME=$(basename $SQLBZ2)
    OUTPUT="${OUTPUT_DIR}/${NAME}.out"
    LOG="${OUTPUT_DIR}/${NAME}.log"
    JUNITNAME=$(basename $SQLBZ2 | sed 's/\./_/g')
    ERROR=$(check_error "$OUTPUT" "$LOG")

    if [ -z "$ERROR" ]; then
      echo "  <testcase class=\"CivicrmUpgradeTest\" name=\"CivicrmUpgradeTest.${JUNITNAME}\" />" >> "$JUNIT_XML"
    else
      echo "  <testcase class=\"CivicrmUpgradeTest\" name=\"CivicrmUpgradeTest.${JUNITNAME}\">" >> "$JUNIT_XML"
      echo "    <failure type=\"UnexpectedOutput\">" >> "$JUNIT_XML"
      echo "---- CONSOLE OUTPUT: ----">> "$JUNIT_XML"
      php -r 'echo htmlspecialchars(file_get_contents("php://stdin"));' < $OUTPUT >> "$JUNIT_XML"
      echo "" >> "$JUNIT_XML"
      echo "" >> "$JUNIT_XML"
      echo "---- LOG OUTPUT: ----" >> "$JUNIT_XML"
      php -r 'echo htmlspecialchars(file_get_contents("php://stdin"));' < $LOG >> "$JUNIT_XML"
      echo "    </failure>" >> "$JUNIT_XML"
      echo "  </testcase>" >> "$JUNIT_XML"
    fi
  done

  echo "</testsuite>" >> "$JUNIT_XML"
  echo "</testsuites>" >> "$JUNIT_XML"
fi
