t7510: invoke git as part of &&-chain
[gitweb.git] / t / test-lib.sh
index 14ccb608380f23865ee80bbe2754b858c0c4d639..a1abb1177a15c85ef7c75f0b9b056a59ff9843e9 100644 (file)
@@ -139,6 +139,19 @@ do
                verbose_log=t
                tee=t
                ;;
+       --stress)
+               stress=t ;;
+       --stress=*)
+               stress=${opt#--*=}
+               case "$stress" in
+               *[^0-9]*|0*|"")
+                       echo "error: --stress=<N> requires the number of jobs to run" >&2
+                       exit 1
+                       ;;
+               *)      # Good.
+                       ;;
+               esac
+               ;;
        *)
                echo "error: unknown test option '$opt'" >&2; exit 1 ;;
        esac
@@ -160,6 +173,108 @@ then
        test -z "$verbose_log" && verbose=t
 fi
 
+if test -n "$stress"
+then
+       verbose=t
+       trace=t
+       immediate=t
+fi
+
+TEST_STRESS_JOB_SFX="${GIT_TEST_STRESS_JOB_NR:+.stress-$GIT_TEST_STRESS_JOB_NR}"
+TEST_NAME="$(basename "$0" .sh)"
+TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/test-results"
+TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX"
+TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
+test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
+case "$TRASH_DIRECTORY" in
+/*) ;; # absolute path is good
+ *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
+esac
+
+# If --stress was passed, run this test repeatedly in several parallel loops.
+if test "$GIT_TEST_STRESS_STARTED" = "done"
+then
+       : # Don't stress test again.
+elif test -n "$stress"
+then
+       if test "$stress" != t
+       then
+               job_count=$stress
+       elif test -n "$GIT_TEST_STRESS_LOAD"
+       then
+               job_count="$GIT_TEST_STRESS_LOAD"
+       elif job_count=$(getconf _NPROCESSORS_ONLN 2>/dev/null) &&
+            test -n "$job_count"
+       then
+               job_count=$((2 * $job_count))
+       else
+               job_count=8
+       fi
+
+       mkdir -p "$TEST_RESULTS_DIR"
+       stressfail="$TEST_RESULTS_BASE.stress-failed"
+       rm -f "$stressfail"
+
+       stress_exit=0
+       trap '
+               kill $job_pids 2>/dev/null
+               wait
+               stress_exit=1
+       ' TERM INT HUP
+
+       job_pids=
+       job_nr=0
+       while test $job_nr -lt "$job_count"
+       do
+               (
+                       GIT_TEST_STRESS_STARTED=done
+                       GIT_TEST_STRESS_JOB_NR=$job_nr
+                       export GIT_TEST_STRESS_STARTED GIT_TEST_STRESS_JOB_NR
+
+                       trap '
+                               kill $test_pid 2>/dev/null
+                               wait
+                               exit 1
+                       ' TERM INT
+
+                       cnt=0
+                       while ! test -e "$stressfail"
+                       do
+                               $TEST_SHELL_PATH "$0" "$@" >"$TEST_RESULTS_BASE.stress-$job_nr.out" 2>&1 &
+                               test_pid=$!
+
+                               if wait $test_pid
+                               then
+                                       printf "OK   %2d.%d\n" $GIT_TEST_STRESS_JOB_NR $cnt
+                               else
+                                       echo $GIT_TEST_STRESS_JOB_NR >>"$stressfail"
+                                       printf "FAIL %2d.%d\n" $GIT_TEST_STRESS_JOB_NR $cnt
+                               fi
+                               cnt=$(($cnt + 1))
+                       done
+               ) &
+               job_pids="$job_pids $!"
+               job_nr=$(($job_nr + 1))
+       done
+
+       wait
+
+       if test -f "$stressfail"
+       then
+               echo "Log(s) of failed test run(s):"
+               for failed_job_nr in $(sort -n "$stressfail")
+               do
+                       echo "Contents of '$TEST_RESULTS_BASE.stress-$failed_job_nr.out':"
+                       cat "$TEST_RESULTS_BASE.stress-$failed_job_nr.out"
+               done
+               rm -rf "$TRASH_DIRECTORY.stress-failed"
+               # Move the last one.
+               mv "$TRASH_DIRECTORY.stress-$failed_job_nr" "$TRASH_DIRECTORY.stress-failed"
+       fi
+
+       exit $stress_exit
+fi
+
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
 if test "$GIT_TEST_TEE_STARTED" = "done"
@@ -167,12 +282,11 @@ then
        : # do not redirect again
 elif test -n "$tee"
 then
-       mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results"
-       BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)"
+       mkdir -p "$TEST_RESULTS_DIR"
 
        # Make this filename available to the sub-process in case it is using
        # --verbose-log.
-       GIT_TEST_TEE_OUTPUT_FILE=$BASE.out
+       GIT_TEST_TEE_OUTPUT_FILE=$TEST_RESULTS_BASE.out
        export GIT_TEST_TEE_OUTPUT_FILE
 
        # Truncate before calling "tee -a" to get rid of the results
@@ -180,8 +294,8 @@ then
        >"$GIT_TEST_TEE_OUTPUT_FILE"
 
        (GIT_TEST_TEE_STARTED=done ${TEST_SHELL_PATH} "$0" "$@" 2>&1;
-        echo $? >"$BASE.exit") | tee -a "$GIT_TEST_TEE_OUTPUT_FILE"
-       test "$(cat "$BASE.exit")" = 0
+        echo $? >"$TEST_RESULTS_BASE.exit") | tee -a "$GIT_TEST_TEE_OUTPUT_FILE"
+       test "$(cat "$TEST_RESULTS_BASE.exit")" = 0
        exit
 fi
 
@@ -840,12 +954,9 @@ test_done () {
 
        if test -z "$HARNESS_ACTIVE"
        then
-               test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
-               mkdir -p "$test_results_dir"
-               base=${0##*/}
-               test_results_path="$test_results_dir/${base%.sh}.counts"
+               mkdir -p "$TEST_RESULTS_DIR"
 
-               cat >"$test_results_path" <<-EOF
+               cat >"$TEST_RESULTS_BASE.counts" <<-EOF
                total $test_count
                success $test_success
                fixed $test_fixed
@@ -1051,12 +1162,6 @@ then
 fi
 
 # Test repository
-TRASH_DIRECTORY="trash directory.$(basename "$0" .sh)"
-test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
-case "$TRASH_DIRECTORY" in
-/*) ;; # absolute path is good
- *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
-esac
 rm -fr "$TRASH_DIRECTORY" || {
        GIT_EXIT_OK=t
        echo >&5 "FATAL: Cannot prepare test area"