Merge pull request #15301 from mikedn/cast-un
[platform/upstream/coreclr.git] / tests / runtesttilstable.sh
1 #!/usr/bin/env bash
2
3 function print_usage {
4     echo ''
5     echo 'CoreCLR test runner wrapper script.'
6     echo ''
7     echo 'Run tests using runtest.sh, then rerun the failures, if any,'
8     echo 'until the number of failures stabilizes. Thus, when running'
9     echo 'flaky tests, or running tests on a flaky platform, only the'
10     echo 'repeatable, "real", failures are reported.'
11     echo ''
12     echo 'Tests are rerun in sequential mode (passing --sequential to runtest.sh).'
13     echo 'This hopefully avoids resource exhaustion and other parallel run problems.'
14     echo ''
15     echo 'A maximum number of iterations can be specified.'
16     echo ''
17     echo 'Command line:'
18     echo ''
19     echo 'runtesttilstable.sh [options] [arguments for runtest.sh]'
20     echo ''
21     echo 'Any unknown argument is passed directly to runtest.sh.'
22     echo ''
23     echo 'Optional arguments:'
24     echo '  -h|--help                        : Show usage information.'
25     echo '  --max-iterations=<count>         : Specify the maximum number of iterations. Default: 4.'
26     echo ''
27 }
28
29 function exit_with_error {
30     local errorMessage=$1
31     local printUsage=$2
32
33     if [ -z "$printUsage" ]; then
34         ((printUsage = 0))
35     fi
36
37     echo "$errorMessage"
38     if ((printUsage != 0)); then
39         print_usage
40     fi
41     exit $EXIT_CODE_EXCEPTION
42 }
43
44 # Handle Ctrl-C. We will stop execution and print the results that
45 # we gathered so far.
46 function handle_ctrl_c {
47     echo ""
48     echo "*** Stopping... ***"
49     print_results
50     exit_with_error "Test run aborted by Ctrl+C."
51 }
52
53 # Register the Ctrl-C handler
54 trap handle_ctrl_c INT
55
56 # Where are we?
57 scriptPath=$(dirname $0)
58
59 # Exit code constants
60 readonly EXIT_CODE_SUCCESS=0       # Script ran normally.
61 readonly EXIT_CODE_EXCEPTION=1     # Script exited because something exceptional happened (e.g. bad arguments, Ctrl-C interrupt).
62 readonly EXIT_CODE_TEST_FAILURE=2  # Script completed successfully, but one or more tests failed.
63
64 # Argument variables
65 ((maxIterations = 4))
66
67 # Handle arguments
68 __UnprocessedBuildArgs=
69
70 # We need to capture the --testRootDir argument so we know where the test pass/fail/skip files will be placed.
71 testRootDir=
72
73 # We need to handle the --playlist argument specially. The first run, we pass it through (if passed).
74 # After that, we use the --playlist argument ourselves, so we don't pass through the original one.
75 playlistArgument=
76
77 for i in "$@"
78 do
79     case $i in
80         -h|--help)
81             print_usage
82             exit $EXIT_CODE_SUCCESS
83             ;;
84         --max-iterations=*)
85             maxIterations=${i#*=}
86             ;;
87         --playlist=*)
88             playlistArgument=$i
89             ;;
90         --testRootDir=*)
91             testRootDir=${i#*=}
92             # Also pass it on to runtest.sh
93             __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
94             ;;
95         *)
96             __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
97             ;;
98     esac
99 done
100
101 # Check testRootDir; this check is also done by runtest.sh.
102
103 if [ -z "$testRootDir" ]; then
104     echo "--testRootDir is required."
105     print_usage
106     exit $EXIT_CODE_EXCEPTION
107 fi
108 if [ ! -d "$testRootDir" ]; then
109     echo "Directory specified by --testRootDir does not exist: $testRootDir"
110     exit $EXIT_CODE_EXCEPTION
111 fi
112
113 # Now start running the tests.
114
115 nextcmd="${scriptPath}/runtest.sh ${playlistArgument} ${__UnprocessedBuildArgs}"
116 echo "Running: $nextcmd"
117 $nextcmd
118 exitCode=$?
119 if [ $exitCode -eq $EXIT_CODE_TEST_FAILURE ]; then
120     # Now, we loop, rerunning the failed tests up to maxIterations times minus one
121     # (the initial run counts as an iteration).
122     ((totalRerunCount = $maxIterations - 1))
123     for (( i=1; i<=$totalRerunCount; i++ )); do
124         if [ ! -e "$testRootDir/coreclrtests.fail.txt" ]; then
125             exit_with_error "Error: couldn't find $testRootDir/coreclrtests.fail.txt"
126         fi
127
128         num_errors=$(grep -c '' "$testRootDir/coreclrtests.fail.txt")
129         echo "Test run failed with $num_errors errors:"
130         cat "$testRootDir/coreclrtests.fail.txt"
131         echo ''
132
133         echo "Rerunning failures ($i of $totalRerunCount reruns)..."
134
135         # Move the fail file to a different location, so it can be used without getting trashed by the
136         # next run's error file.
137         retryFile="$testRootDir/coreclrtests.retry.txt"
138         if [ -e "$retryFile" ]; then
139             rm -f "$retryFile"
140             if [ -e "$retryFile" ]; then
141                 exit_with_error "Error: couldn't delete $retryFile"
142             fi
143         fi
144         mv "$testRootDir/coreclrtests.fail.txt" "$retryFile"
145
146         nextcmd="${scriptPath}/runtest.sh --sequential --playlist=${retryFile} ${__UnprocessedBuildArgs}"
147         echo "Running: $nextcmd"
148         $nextcmd
149         exitCode=$?
150         if [ $exitCode -ne $EXIT_CODE_TEST_FAILURE ]; then
151             # Either success or exceptional failure; we're done. For test failure, we loop,
152             # if we haven't hit the maximum number of allowed iterations.
153             break
154         fi
155     done
156 fi
157
158 exit $exitCode