5 echo 'CoreCLR test runner wrapper script.'
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.'
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.'
15 echo 'A maximum number of iterations can be specified.'
19 echo 'runtesttilstable.sh [options] [arguments for runtest.sh]'
21 echo 'Any unknown argument is passed directly to runtest.sh.'
23 echo 'Optional arguments:'
24 echo ' -h|--help : Show usage information.'
25 echo ' --max-iterations=<count> : Specify the maximum number of iterations. Default: 4.'
29 function exit_with_error {
33 if [ -z "$printUsage" ]; then
38 if ((printUsage != 0)); then
41 exit $EXIT_CODE_EXCEPTION
44 # Handle Ctrl-C. We will stop execution and print the results that
46 function handle_ctrl_c {
48 echo "*** Stopping... ***"
50 exit_with_error "Test run aborted by Ctrl+C."
53 # Register the Ctrl-C handler
54 trap handle_ctrl_c INT
57 scriptPath=$(dirname $0)
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.
68 __UnprocessedBuildArgs=
70 # We need to capture the --testRootDir argument so we know where the test pass/fail/skip files will be placed.
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.
82 exit $EXIT_CODE_SUCCESS
92 # Also pass it on to runtest.sh
93 __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
96 __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
101 # Check testRootDir; this check is also done by runtest.sh.
103 if [ -z "$testRootDir" ]; then
104 echo "--testRootDir is required."
106 exit $EXIT_CODE_EXCEPTION
108 if [ ! -d "$testRootDir" ]; then
109 echo "Directory specified by --testRootDir does not exist: $testRootDir"
110 exit $EXIT_CODE_EXCEPTION
113 # Now start running the tests.
115 nextcmd="${scriptPath}/runtest.sh ${playlistArgument} ${__UnprocessedBuildArgs}"
116 echo "Running: $nextcmd"
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"
128 num_errors=$(grep -c '' "$testRootDir/coreclrtests.fail.txt")
129 echo "Test run failed with $num_errors errors:"
130 cat "$testRootDir/coreclrtests.fail.txt"
133 echo "Rerunning failures ($i of $totalRerunCount reruns)..."
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
140 if [ -e "$retryFile" ]; then
141 exit_with_error "Error: couldn't delete $retryFile"
144 mv "$testRootDir/coreclrtests.fail.txt" "$retryFile"
146 nextcmd="${scriptPath}/runtest.sh --sequential --playlist=${retryFile} ${__UnprocessedBuildArgs}"
147 echo "Running: $nextcmd"
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.