#!/bin/bash
# Uncomment next line to print each bash command before it is executed
#set -x

# function to list failing test in ctest log file
# first argument = file to check
listFailedTests() {
    echo "$(grep -e "\*\*\*Failed" -e "SegFault" -e "\*\*\****Exception" -e "\*\*\*Timeout" $1 )"
}

# Path needs to use forward slashes
# This is ok on Linux but since gitlab-runner 11.7 on windows all path variables use backward slash instead of forward slash
# → Replace all backslash to forward slash 
export PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR//\\//}
export CI_PROJECT_DIR=${CI_PROJECT_DIR//\\//}

echo "Job $CI_JOB_NAME"
echo "PROJECT_SOURCE_DIR=$PROJECT_SOURCE_DIR"
echo "CI_PROJECT_DIR=$CI_PROJECT_DIR"

if ! grep -q TRIGGER_STAGE_TEST "${PROJECT_LOG_DIR}/trigger-stage.txt"; then
    echo "Job skipped as /test flag not in commit message and CAMITK_CI_STAGE < $STAGE_CONFIGURE"; 
    exit 1;
fi

if [[ "$OS" != "win10" ]]; then
    echo "===== Configuring xvfb =====" > >(tee --append ${PROJECT_LOG_DIR}/test.log) 2>&1
    # Starts the server first (try to avoid unexpected and random "QXcbConnection: Could not connect to display :99")
    export DISPLAY=":98"
    # create a specific file for xauth
    export XAUTHORITY=$(mktemp)
    # remove +iglx for now 
    Xvfb $DISPLAY -screen 0 1280x1024x16 -ac -nolisten tcp -nolisten unix -auth $XAUTHORITY & > >(tee --append ${PROJECT_LOG_DIR}/test.log) 2>&1
    trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
    # give some times to start the Xvfb
    sleep 10
    # On linux, use QT_QPA_PLATFORM=xcb (and not offscreen)
    # see also https://doc.qt.io/qt-5/embedded-linux.html#linuxfb 
    export QT_QPA_FONTDIR=/usr/share/fonts/truetype/dejavu
    export QT_QPA_PLATFORM=xcb
fi

echo "===== Running ctest ====="

ctest --extra-verbose \
      --output-on-failure \
      -DCTEST_SITE="$CDASH_SITE" \
      -DCI_MODE="$CAMITK_CI_MODE" \
      -DCI_ID="P $CI_PIPELINE_ID - J $CI_BUILD_ID" \
      -DCI_BRANCH="$CI_COMMIT_REF_NAME" \
      -DCI_BUILD_SETTINGS="$COMPILER_CONFIG" \
      -DCI_PROJECT_LOG_DIRECTORY="$CI_PROJECT_DIR/$PROJECT_LOG_DIR" \
      -DCTEST_SOURCE_DIRECTORY="$PROJECT_SOURCE_DIR" \
      -DCTEST_BINARY_DIRECTORY="$PROJECT_BUILD_DIR" \
      -S $PROJECT_SOURCE_DIR/sdk/cmake/ctest/ci-test.cmake > >(tee --append ${PROJECT_LOG_DIR}/test.log | grep --line-buffered -e "Test \#") 2>&1

# Using ctest with its --rerun-failed flag in order to only rerun the failed tests 
# seems to be buggy.
# See CMake bugs:
# - https://gitlab.kitware.com/cmake/cmake/issues/17767
# - https://gitlab.kitware.com/cmake/cmake/issues/16314
# Otherwise it would only requires to add the following lines:
#     echo "===== Re-running failed tests ====="
#     ctest --extra-verbose \
#         --rerun-failed \
#         -DCTEST_SITE="$CDASH_SITE" \
#         -DCI_MODE="$CAMITK_CI_MODE" \
#         -DCI_ID="P $CI_PIPELINE_ID - J $CI_BUILD_ID" \
#         -DCI_BRANCH="$CI_COMMIT_REF_NAME" \
#         -DCI_BUILD_SETTINGS="$COMPILER_CONFIG" \
#         -DCI_PROJECT_LOG_DIRECTORY="$CI_PROJECT_DIR/$PROJECT_LOG_DIR" \
#         -DCTEST_SOURCE_DIRECTORY="$PROJECT_SOURCE_DIR" \
#         -DCTEST_BINARY_DIRECTORY="$PROJECT_BUILD_DIR" \
#         -S $PROJECT_SOURCE_DIR/sdk/cmake/ctest/ci-test.cmake > >(tee --append ${PROJECT_LOG_DIR}/test.log | grep --line-buffered -e "Test \#") 2>&1

# So as for now, parse the log and do a manual rerun
echo
echo "===== Not run (disabled) tests ====="
grep -e "Not Run" $CI_PROJECT_DIR/$PROJECT_LOG_DIR/test.log

# as ctest return a strange 255 error, check the log
if grep --quiet "Fatal error" $CI_PROJECT_DIR/$PROJECT_LOG_DIR/ci-test.log; then
    echo
    echo "===== Fatal errors ====="
    echo "Found fatal error in $CI_PROJECT_DIR/$PROJECT_LOG_DIR/ci-test.log"
    echo 
    
    testToReRun=$(listFailedTests $CI_PROJECT_DIR/$PROJECT_LOG_DIR/test.log)
    nrOfFailed=$(echo "$testToReRun" | wc -l)
    echo "===== $nrOfFailed failed test(s) ====="
    echo "$testToReRun"
    echo
    
    echo "===== Re-running failed tests ====="
    echo "Checking $CI_PROJECT_DIR/$PROJECT_LOG_DIR/test.log for failed test" > ${PROJECT_LOG_DIR}/rerun-test.log
    echo "" >> ${PROJECT_LOG_DIR}/rerun-test.log
    # loop over failed tests
    echo "$testToReRun" | while IFS= read -r line; do 
        testname=$(echo $line | sed -r 's/.+[0-9]+:\s(.*)\s\..*/\1/g' | cut -f1 -d" ")
        echo "Re-running $testname..." > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1

        reason=$(echo $line | sed -r 's/.*\s\.\.\.(.*)/\1/g')
        echo "Reason:" > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1
        # add ----> at the beginning of the line to distinguished real error log during rerunning 
        echo "----> $reason" > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1
        echo "" > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1
        
        echo "Exact command:"  >> ${PROJECT_LOG_DIR}/rerun-test.log
        echo "ctest --extra-verbose \
              --output-on-failure \
              -DCTEST_SITE=\"$CDASH_SITE\" \
              -DCI_MODE=\"$CAMITK_CI_MODE\" \
              -DCI_ID=\"P $CI_PIPELINE_ID - J $CI_BUILD_ID\" \
              -DCI_BRANCH=\"$CI_COMMIT_REF_NAME\" \
              -DCI_BUILD_SETTINGS=\"$COMPILER_CONFIG\" \
              -DCI_PROJECT_LOG_DIRECTORY=\"$CI_PROJECT_DIR/$PROJECT_LOG_DIR\" \
              -DCTEST_SOURCE_DIRECTORY=\"$PROJECT_SOURCE_DIR\" \
              -DCTEST_BINARY_DIRECTORY=\"$PROJECT_BUILD_DIR\" \
              -DRERUN_TESTNAME=$testname \
              -S $PROJECT_SOURCE_DIR/sdk/cmake/ctest/ci-rerun.cmake > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log | grep --line-buffered -e \"Test \#\") 2>&1"  >> ${PROJECT_LOG_DIR}/rerun-test.log

        echo "Re-run test result:" > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1
        ctest --extra-verbose \
              --output-on-failure \
              -DCTEST_SITE="$CDASH_SITE" \
              -DCI_MODE="$CAMITK_CI_MODE" \
              -DCI_ID="P $CI_PIPELINE_ID - J $CI_BUILD_ID" \
              -DCI_BRANCH="$CI_COMMIT_REF_NAME" \
              -DCI_BUILD_SETTINGS="$COMPILER_CONFIG" \
              -DCI_PROJECT_LOG_DIRECTORY="$CI_PROJECT_DIR/$PROJECT_LOG_DIR" \
              -DCTEST_SOURCE_DIRECTORY="$PROJECT_SOURCE_DIR" \
              -DCTEST_BINARY_DIRECTORY="$PROJECT_BUILD_DIR" \
              -DRERUN_TESTNAME=$testname \
              -S $PROJECT_SOURCE_DIR/sdk/cmake/ctest/ci-rerun.cmake > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log | grep --line-buffered -e "Test \#") 2>&1
        
        echo > >(tee --append ${PROJECT_LOG_DIR}/rerun-test.log) 2>&1
    done
    
    # check the rerun log (listFailedTests but remove the reason lines added in the lg)
    reRunFailed=$(listFailedTests ${PROJECT_LOG_DIR}/rerun-test.log | grep "^[^-].*" | grep -v "^Re-running")
    nrOfFailed=$(echo "$testToReRun" | wc -l)
    if test -z "$reRunFailed"; then
        echo "===== All re-ran tests passed ====="
        echo "Job passed"
        echo
    else
        echo
        echo "===== Fatal errors in re-ran tests ====="
        echo "Found fatal error in re-run test log $CI_PROJECT_DIR/$PROJECT_LOG_DIR/rerun-test.log"
        echo 
        
        
        echo "$nrOfFailed failed test(s) during reran:"
        echo "$reRunFailed" | while IFS= read -r line; do
            echo -n "- "
            echo $line | sed -r 's/.+[0-9]+:\s(.*)\s\..*/\1/g' | cut -f1 -d" "
        done
        echo
        echo "Job failed"
        echo
        
        # send error to the pipeline
        exit 1
    fi
else
    echo "===== All tests passed ====="
    echo "Everything OK. No test needed to be re-ran."
    echo
    echo "Job passed"
    echo
fi
