From 87379d7e50a51c9dad25ce6b12b22a6db3fea19b Mon Sep 17 00:00:00 2001
From: Andrei Stepanov <astepano@redhat.com>
Date: Apr 25 2019 16:57:52 +0000
Subject: Script for run tests in Basic role.


Tested with:

- hosts: localhost
  roles:
  - role: standard-test-basic
    tags:
    - classic
    tests:
    - test one:
        dir: "tdir for test 1"
        run: XXXXXXXXX="1 2 3 4 " env
    - test 2:
        dir: tdir two
        run: true; false
    - test 3 three:
        dir: dir3
        run: echo -e "hello world\nnewline"; exit 111

Signed-off-by: Andrei Stepanov <astepano@redhat.com>

---

diff --git a/roles/standard-test-basic/files/run-basic-test b/roles/standard-test-basic/files/run-basic-test
new file mode 100755
index 0000000..5bc42bc
--- /dev/null
+++ b/roles/standard-test-basic/files/run-basic-test
@@ -0,0 +1,142 @@
+#!/bin/bash -efu
+
+# Called from standard-test-basic role to run basic tests
+# This script is copied to test-environment.
+
+debug() {
+    if [ -n "$DEBUG" ]; then
+        echo "$*" >&2
+    fi
+}
+
+msg_usage() {
+    cat << EOF
+
+Run basic test.
+
+Usage:
+$PROG <options>
+
+Options:
+-h, --help              display this help and exit
+-v, --verbose           turn on debug
+-w, --workdir           test environment work dir. Directory for test execution.
+-a, --artifactsdir      test environment dir to store artifacts
+-t, --testname          name of the test
+-c, --cmd               shell command to run the test
+EOF
+}
+
+# Entry
+
+PROG="${PROG:-${0##*/}}"
+DEBUG="${DEBUG:-}"
+STR_CMD="${STR_CMD:-}"
+STR_DEBUG="${STR_DEBUG:-}"
+STR_VERBOSE="${STR_VERBOSE:-}"
+STR_WORKDIR="${STR_WORKDIR:-}"
+STR_TEST_NAME="${STR_TEST_NAME:-}"
+STR_ARTIFACTS_DIR="${STR_ARTIFACTS_DIR:-/tmp}"
+
+# http://wiki.bash-hackers.org/howto/getopts_tutorial
+opt=$(getopt -n "$0" --options "hvt:w:a:c:" --longoptions "help,verbose,cmd:,testname:,workdir:,artifactsdir:" -- "$@")
+eval set -- "$opt"
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        -t|--testname)
+            STR_TEST_NAME="$2"
+            shift 2
+            ;;
+        -c|--cmd)
+            STR_CMD="$2"
+            shift 2
+            ;;
+        -w|--workdir)
+            STR_WORKDIR="$2"
+            shift 2
+            ;;
+        -a|--artifactsdir)
+            STR_ARTIFACTS_DIR="$2"
+            shift 2
+            ;;
+        -v|--verbose)
+            DEBUG="-v"
+            shift
+            ;;
+        -h|--help)
+            msg_usage
+            exit 0
+            ;;
+        --)
+            shift
+            ;;
+        *)
+            msg_usage
+            exit 1
+    esac
+done
+
+# Entry
+
+if [ -z "$STR_TEST_NAME" ] || [ -z "$STR_WORKDIR" ] || [ -z "$STR_CMD" ]; then
+    echo "Use: $PROG -h for help."
+    exit 0
+fi
+
+mkdir -p "$STR_WORKDIR"
+mkdir -p "$STR_ARTIFACTS_DIR"
+STR_WORKDIR="$(realpath "$STR_WORKDIR")"
+STR_ARTIFACTS_DIR="$(realpath "$STR_ARTIFACTS_DIR")"
+debug "Test: $STR_TEST_NAME"
+debug "Command: $STR_CMD"
+debug "Work dir: $STR_WORKDIR"
+debug "Artifacts dir: $STR_ARTIFACTS_DIR"
+
+# Up to this point any fail is considered as ci-sytem fail. Exit code != 0.
+# Starting from this point and bellow any fail is considered as a test fail. Exit code == 0.
+
+clean_exit() {
+    rc=$?;
+    trap - SIGINT SIGTERM SIGABRT EXIT # clear the trap
+    echo "Run test '$STR_TEST_NAME': done. Test's exit code: $rc"
+    # Exit code == 0, no matter of the test result.
+    # Close tee pipes
+    for pid in $(ps -o pid --no-headers --ppid $$); do
+        if [ -n "$(ps -p $pid -o pid=)" ]; then
+            kill -s HUP $pid
+        fi
+    done
+    # Return non-zero when test command not found
+    if [[ $rc -eq 127 ]]; then
+        echo "$STR_TEST_NAME (problem with test execution)" >&2
+    fi
+    local status="FAIL"
+    if [[ $rc -eq 0 ]]; then
+        status="PASS"
+    fi
+    local run_journal="$STR_ARTIFACTS_DIR/test.log"
+    echo "${status} $STR_TEST_NAME" >> "$run_journal"
+    if [ -e "$logfile_stdout" ]; then
+        local new_logfile_stdout="$(dirname "$logfile_stdout")/${status}_str_$(basename "$logfile_stdout")"
+        mv -f "$logfile_stdout" "$new_logfile_stdout"
+    fi
+    exit 0
+}
+trap clean_exit SIGINT SIGTERM SIGABRT EXIT
+
+export PATH="$PATH:$STR_WORKDIR"
+mkdir -p "$STR_ARTIFACTS_DIR"
+logfile_stdout="$STR_ARTIFACTS_DIR/$(echo "$STR_TEST_NAME" | sed -e 's/\//-/g').log"
+logfile_stderr="$STR_ARTIFACTS_DIR/$(echo "$STR_TEST_NAME" | sed -e 's/\//-/g')-err.log"
+logfile_stdout="$(realpath "$logfile_stdout")"
+logfile_stderr="$(realpath "$logfile_stderr")"
+exec 3>&1 4>&2 1> >(tee -a "$logfile_stdout" >&3) 2> >(tee -a "$logfile_stderr" >&4)
+cd "$STR_WORKDIR"
+# Purpose to spawn new bash is to ignore -efu setting for current shell
+# Test command: run-basic-test -w wodir -c 'false; echo 123; echo 333 >&2; touch "123 123"; exit 43' -t my_test -a logs -v
+if [ -f "$STR_CMD" ]; then
+    chmod 0775 "$STR_CMD"
+fi
+bash -c "$STR_CMD"
+# Explicit return code
+exit $?
diff --git a/roles/standard-test-basic/tasks/main.yml b/roles/standard-test-basic/tasks/main.yml
index d51e295..692b6f1 100644
--- a/roles/standard-test-basic/tasks/main.yml
+++ b/roles/standard-test-basic/tasks/main.yml
@@ -2,48 +2,12 @@
 
 - block:
   - name: Execute tests
-    shell: |
-      if [[ -z ${TEST} ]]; then
-          echo "FAIL: Test case name is not set" >> {{ remote_artifacts }}/test.log
-          exit
-      fi
-      if [[ -z ${TEST_DIR} ]]; then
-          echo "FAIL: Test directory for $TEST not found" >> {{ remote_artifacts }}/test.log
-          exit
-      fi
-      if [[ -z ${TEST_CMD} ]]; then
-          echo "FAIL: Does not know how to run $TEST" >> {{ remote_artifacts }}/test.log
-          exit
-      fi
-      log_file_name=$(echo $TEST | sed -e 's/\//-/g').log
-      logfile={{ remote_artifacts }}/str_${log_file_name}
-      exec 2>>$logfile 1>>$logfile
-      cd $TEST_DIR
-      #if command is a file make it executable
-      cmd="$(echo $TEST_CMD | awk '{print $1;}')"
-      if [ -f "$cmd" ]; then
-          chmod 0775 "$cmd"
-      fi
-      status="FAIL"
-      #execute the test
-      eval $TEST_CMD
-      if [ $? -eq 0 ]; then
-          status="PASS"
-      fi
-      echo "${status} $TEST" >> {{ remote_artifacts }}/test.log
-      # Add test status as prefix to test case log
-      mv ${logfile} {{ remote_artifacts }}/${status}_str_${log_file_name}
-    environment:
-    #Allow to use tests as a simple string which means the test is expected
-    #to be in a directory with same name and test script `runtest.sh`
-    #It is also possible to define the test as dictionary, in that case it is possible
-    #to change test directory and test command line parameters while test name is item key
-      TEST:
-        "{{ item if item.keys is not defined else (item.keys()|list)[0] }}"
-      TEST_DIR:
-        "{{ tenv_workdir }}/{{ item if item.keys is not defined else item[(item.keys()|list)[0]]['dir']|default((item.keys()|list)[0]) }}"
-      TEST_CMD:
-        "{{'./runtest.sh' if item.keys is not defined else item[(item.keys()|list)[0]]['run']|default('./runtest.sh')}}"
+    script:
+        run-basic-test -v
+                --workdir {{ tenv_workdir | regex_escape() }}/{{ item if item.keys is not defined else item[(item.keys()|list)[0]]['dir']|default((item.keys()|list)[0]) | regex_escape() }}
+                --artifactsdir {{ remote_artifacts | regex_escape() }}
+                --test {{ item if item.keys is not defined else (item.keys()|list)[0] | regex_escape() }}
+                --cmd {{ './runtest.sh' if item.keys is not defined else item[(item.keys()|list)[0]]['run']|default('./runtest.sh') | regex_escape() }}
     with_items:
     - "{{ tests }}"
 

