3 # Licensed to the Apache Software Foundation (ASF) under one
4 # or more contributor license agreements. See the NOTICE file
5 # distributed with this work for additional information
6 # regarding copyright ownership. The ASF licenses this file
7 # to you under the Apache License, Version 2.0 (the
8 # "License"); you may not use this file except in compliance
9 # with the License. You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
21 # - analyse the content of the .java test file to split them between
23 # - launch the small tests in a single maven, with surefire
24 # parallelisation activated
25 # - launch the medium & large in two maven, parallelized
26 # - the flaky tests are run at the end, not parallelized
27 # - present a small report of the global results
28 # - copy the failed test reports with prefix 'fail_' and a timestamp
29 # to protect them from a later deletion by maven
30 # - if configured for, relaunch the tests in errors
34 # - multiple maven are launch, hence there can be recompilation
35 # between the tests if a file is modified. For non flaky tests and
36 # parallelization, the frame is the time to execute the small tests,
37 # so it's around 4 minutes.
38 # - Note that surefire is buggy, and the results presented while
39 # running may be wrong. For example, it can says that a class tests
40 # have 5 errors. When you look at the file it wrote, it says that the
41 # 2 tests are ok, and in the class there are actually two tests
42 # methods, not five. If you generate the report at the end with
43 # surefire-report it's fine however.
45 ######################################### parameters
47 #mvn test -Dtest=org.apache.hadoop.hbase.regionserver.TestScanWithBloomError $*
51 #set to 0 to run only developpers tests (small & medium categories)
54 #set to 1 to replay the failed tests. Previous reports are kept in
58 #set to 0 to run all medium & large tests in a single maven operation
62 #harcoded list of tests that often fail. We don't want to add any
63 # complexity around then so there are not run in parallel but after
65 #The ',' at the end is mandatory
67 #org.apache.hadoop.hbase.mapreduce.TestTableInputFormatScan,org.apache.hadoop.hbase.catalog.TestMetaTableAccessorNoCluster,org.apache.hadoop.hbase.catalog.TestMetaTableAccessor,org.apache.hadoop.hbase.mapreduce.TestHFileOutputFormat,org.apache.hadoop.hbase.mapred.TestTableMapReduce,org.apache.hadoop.hbase.coprocessor.TestMasterCoprocessorExceptionWithAbort,org.apache.hadoop.hbase.coprocessor.TestMasterCoprocessorExceptionWithRemove,org.apache.hadoop.hbase.client.TestAdmin,org.apache.hadoop.hbase.master.TestMasterFailover,org.apache.hadoop.hbase.regionserver.wal.TestLogRolling,org.apache.hadoop.hbase.master.TestDistributedLogSplitting,org.apache.hadoop.hbase.master.TestMasterRestartAfterDisablingTable,org.apache.hadoop.hbase.TestGlobalMemStoreSize,
69 ######################################### Internal parameters
70 #directory used for surefire & the source code.
71 #They should not need to be modified
72 #The final / is mandatory
73 rootTestClassDirectory
="./src/test/java/"
74 surefireReportDirectory
="./target/surefire-reports/"
76 #variable to use to debug the script without launching the tests
78 #mvnCommand="echo $mvnCommand"
80 ######################################### Functions
81 #get the list of the process considered as dead
82 # i.e.: in the same group as the script and with a ppid of 1
83 # We do this because surefire can leave some dead process, so
84 # we will jstack them and kill them
85 function createListDeadProcess
{
89 #list of the process with a ppid of 1
90 sonProcess
=`ps -o pid= --ppid 1`
92 #then the process with a pgid of the script
93 for pId
in $sonProcess
95 pgid
=`ps -o pgid= --pid $pId | sed 's/ //g'`
96 if [ "$pgid" == "$id" ]
98 listDeadProcess
="$pId $listDeadProcess"
103 #kill the java sub process, if any, with a kill and a kill -9
104 #When maven/surefire fails, it lefts some process with a ppid==1
105 #we're going to find them with the pgid, print the stack and kill them.
106 function cleanProcess
{
109 createListDeadProcess
110 for pId
in $listDeadProcess
112 echo "$pId survived, I will kill if it's a java process. 'ps' says:"
114 name
=`ps -o comm= --pid $pId`
115 if [ "$name" == "java" ]
117 echo "$pId, java sub process of $id, is still running, killing it with a standard kill"
118 echo "Stack for $pId before kill:"
121 echo "kill sent, waiting for 30 seconds"
123 son
=`ps -o pid= --pid $pId | wc -l`
126 echo "$pId, java sub process of $id, is still running after a standard kill, using kill -9 now"
127 echo "Stack for $pId before kill -9:"
130 echo "kill sent, waiting for 2 seconds"
132 echo "Process $pId killed by kill -9"
134 echo "Process $pId killed by standard kill -15"
137 echo "$pId is not a java process (it's $name), I don't kill it."
141 createListDeadProcess
142 if (test ${#listDeadProcess} -gt 0)
144 echo "There are still $sonProcess for process $id left."
146 echo "Process $id clean, no son process left"
150 #count the number of ',' in a string
151 # used to calculate the number of class
153 function countClasses
{
154 cars
=`echo $1 | sed 's/[^,]//g' | wc -c `
159 ######################################### script
160 echo "Starting Script. Possible parameters are: runAllTests, replayFailed, nonParallelMaven"
161 echo "Other parameters are sent to maven"
163 #We will use this value at the end to calculate the execution time
166 #look in the arguments if we override default values
169 if [ $arg == "runAllTests" ]
173 if [ $arg == "replayFailed" ]
177 if [ $arg == "nonParallelMaven" ]
189 testsList
=$
(find $rootTestClassDirectory -name "Test*.java")
192 #for all java test files, let see if they contain the pattern
193 # to recognize the category
194 for testFile
in $testsList
196 lenPath
=$
((${#rootTestClassDirectory}))
197 len
=$
((${#testFile} - $lenPath - 5)) # len(".java") == 5
199 shortTestFile
=${testFile:lenPath:$len}
200 testName
=$
(echo $shortTestFile |
sed 's/\//\./g')
202 #The ',' is used in the grep pattern as we don't want to catch
204 isFlaky
=$
((`echo $flakyTests | grep "$testName," | wc -l`))
206 if (test $isFlaky -eq 0)
212 # determine the category of the test by greping into the source code
213 isMedium
=`grep "@Category" $testFile | grep "MediumTests.class" | wc -l`
214 if (test $isMedium -eq 0)
216 isLarge
=`grep "@Category" $testFile | grep "LargeTests.class" | wc -l`
217 if (test $isLarge -eq 0)
219 isSmall
=`grep "@Category" $testFile | grep "SmallTests.class" | wc -l`
220 if (test $isSmall -eq 0)
222 echo "$testName is not categorized, so it won't be tested"
224 #sanity check on small tests
225 isStrange
=`grep "\.startMini" $testFile | wc -l`
226 if (test $isStrange -gt 0)
228 echo "$testFile is categorized as 'small' but contains a .startMini string. Keep it as small anyway, but it's strange."
234 #put the test in the right list
235 if (test $isSmall -gt 0)
237 smallList
="$smallList,$testName"
239 if (test $isMedium -gt 0)
241 mediumList
="$mediumList,$testName"
243 if (test $isLarge -gt 0)
245 largeList
="$largeList,$testName"
251 #remove the ',' at the beginning
252 smallList
=${smallList:1:${#smallList}}
253 mediumList
=${mediumList:1:${#mediumList}}
254 largeList
=${largeList:1:${#largeList}}
256 countClasses
$smallList
257 echo "There are $count small tests"
259 countClasses
$mediumList
260 echo "There are $count medium tests"
262 countClasses
$largeList
263 echo "There are $count large tests"
268 #do we launch only dev or all tests?
269 if (test $runAllTests -eq 1)
271 echo "Running all tests, small, medium and large"
272 longList
="$mediumList,$largeList"
274 echo "Running developper tests only, small and medium categories"
278 #medium and large test can be run in //, so we're
279 #going to create two lists
281 for testClass
in `echo $longList | sed 's/,/ /g'`
283 if (test $nextList -eq 1)
286 runList1
=$runList1,$testClass
289 runList2
=$runList2,$testClass
293 #remove the ',' at the beginning
294 runList1
=${runList1:1:${#runList1}}
295 runList2
=${runList2:1:${#runList2}}
297 #now we can run the tests, at last!
299 echo "Running small tests with one maven instance, in parallel"
300 #echo Small tests are $smallList
301 $mvnCommand -P singleJVMTests
test -Dtest=$smallList $args
304 exeTime
=$
(((`date +%s` - $startTime)/60))
305 echo "Small tests executed after $exeTime minutes"
307 if (test $parallelMaven -gt 0)
309 echo "Running tests with two maven instances in parallel"
310 $mvnCommand -P localTests
test -Dtest=$runList1 $args &
312 #give some time to the fist process if there is anything to compile
314 $mvnCommand -P localTests
test -Dtest=$runList2 $args
316 #wait for forked process to finish
321 exeTime
=$
(((`date +%s` - $startTime)/60))
322 echo "Medium and large (if selected) tests executed after $exeTime minutes"
324 #now the flaky tests, alone, if the list is not empty
325 # we test on size greater then 5 to remove any "," effect
326 if (test $runAllTests -eq 1 && test ${#flakyTests} -gt 5)
328 echo "Running flaky tests"
329 $mvnCommand -P localTests
test -Dtest=$flakyTests $args
331 exeTime
=$
(((`date +%s` - $startTime)/60))
332 echo "Flaky tests executed after $exeTime minutes"
335 echo "Running tests with a single maven instance, no parallelization"
336 $mvnCommand -P localTests
test -Dtest=$runList1,$runList2,$flakyTests $args
338 exeTime
=$
(((`date +%s` - $startTime)/60))
339 echo "Single maven instance tests executed after $exeTime minutes"
342 #let's analyze the results
343 fullRunList
="$smallList,$longList"
345 if (test $runAllTests -eq 1)
347 fullRunList
="$fullRunList,$flakyTests"
350 #single timestamp to ensure files uniquess.
353 #some counters, initialized because they may not be touched
359 for testClass
in `echo $fullRunList | sed 's/,/ /g'`
361 reportFile
=$surefireReportDirectory/$testClass.txt
362 outputReportFile
=$surefireReportDirectory/$testClass-output.txt
364 if [ -s $reportFile ];
366 isError
=`grep FAILURE $reportFile | wc -l`
367 if (test $isError -gt 0)
369 errorList
="$errorList,$testClass"
370 errorCounter
=$
(($errorCounter + 1))
372 #let's copy the files if we want to use it later
373 cp $reportFile "$surefireReportDirectory/fail_$timestamp.$testClass.txt"
374 if [ -s $reportFile ];
376 cp $outputReportFile "$surefireReportDirectory/fail_$timestamp.$testClass"-output.txt
""
380 sucessCounter
=$
(($sucessCounter +1))
383 #report file does not exist or is empty => the test didn't finish
384 notFinishedCounter
=$
(($notFinishedCounter + 1))
385 notFinishedList
="$notFinishedList,$testClass"
389 #list of all tests that failed
390 replayList
="$notFinishedList""$errorList"
392 #remove the ',' at the beginning
393 notFinishedList
=${notFinishedList:1:${#notFinishedList}}
394 errorList
=${errorList:1:${#errorList}}
395 replayList
=${replayList:1:${#replayList}}
397 #make it simpler to read by removing the org.* stuff from the name
398 notFinishedPresList
=`echo $notFinishedList | sed 's/org.apache.hadoop.hbase.//g' | sed 's/,/, /g'`
399 errorPresList
=`echo $errorList | sed 's/org.apache.hadoop.hbase.//g' | sed 's/,/, /g'`
402 #calculate the execution time
404 exeTime
=$
((($curTime - $startTime)/60))
406 echo "##########################"
407 echo "$sucessCounter tests executed successfully"
408 echo "$errorCounter tests are in error"
409 echo "$notFinishedCounter tests didn't finish"
411 echo "Tests in error are: $errorPresList"
412 echo "Tests that didn't finish are: $notFinishedPresList"
414 echo "Execution time in minutes: $exeTime"
415 echo "##########################"
418 if (test ${#replayList} -gt 0)
420 if (test $replayFailed -gt 0)
422 echo "Replaying all tests that failed"
423 $mvnCommand -P localTests
test -Dtest=$replayList $args
424 echo "Replaying done"