Repository: maven-surefire Updated Branches: refs/heads/master 1cdf49dc2 -> 2bdeeaf1a
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java index f3fcc0b..3c2fa86 100644 --- a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java +++ b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; @@ -38,6 +39,7 @@ import org.apache.maven.surefire.group.parse.ParseException; import org.junit.experimental.categories.Category; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; +import sun.security.krb5.internal.crypto.Des; /** * @author Todd Lipcon @@ -102,6 +104,11 @@ public class FilterFactory return new MethodFilter( requestedTestMethod ); } + public Filter createFailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodMap ) + { + return new FailingMethodFilter( failingClassMethodMap ); + } + public Filter and( Filter filter1, Filter filter2 ) { return new AndFilter( filter1, filter2 ); @@ -144,6 +151,56 @@ public class FilterFactory } } + // Only run test methods in the given input map, indexed by test class + private static class FailingMethodFilter + extends Filter + { + // Map from Class -> List of method names. Are the method names hashed to include the signature? + private final Map<Class<?>, Set<String>> failingClassMethodMap; + + public FailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodMap ) + { + this.failingClassMethodMap = failingClassMethodMap; + } + + @Override + public boolean shouldRun( Description description ) + { + return isDescriptionMatch( description ); + } + + private boolean isDescriptionMatch( Description description ) + { + if ( description.getTestClass() == null || description.getMethodName() == null ) + { + for ( Description childrenDescription : description.getChildren() ) + { + if ( isDescriptionMatch( childrenDescription ) ) + { + return true; + } + } + return false; + } + + Set<String> testMethods = failingClassMethodMap.get( description.getTestClass() ); + if ( testMethods == null ) + { + return false; + } + else + { + return testMethods.contains( description.getMethodName() ); + } + } + + @Override + public String describe() + { + return "By failing class method"; + } + } + private static class GroupMatcherCategoryFilter extends Filter { http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java index a03c7d2..03012bd 100644 --- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java +++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java @@ -19,14 +19,12 @@ package org.apache.maven.surefire.junit4; * under the License. */ -import java.lang.reflect.Method; -import java.util.Iterator; -import java.util.List; - import org.apache.maven.shared.utils.io.SelectorUtils; +import org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil; import org.apache.maven.surefire.common.junit4.JUnit4RunListener; import org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory; import org.apache.maven.surefire.common.junit4.JUnit4TestChecker; +import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener; import org.apache.maven.surefire.providerapi.AbstractProvider; import org.apache.maven.surefire.providerapi.ProviderParameters; import org.apache.maven.surefire.report.ConsoleOutputCapture; @@ -43,12 +41,19 @@ import org.apache.maven.surefire.util.RunOrderCalculator; import org.apache.maven.surefire.util.ScanResult; import org.apache.maven.surefire.util.TestsToRun; import org.apache.maven.surefire.util.internal.StringUtils; - import org.junit.runner.Request; import org.junit.runner.Result; import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * @author Kristian Rosenvold */ @@ -71,6 +76,8 @@ public class JUnit4Provider private final ScanResult scanResult; + private final int rerunFailingTestsCount; + public JUnit4Provider( ProviderParameters booterParameters ) { @@ -82,7 +89,7 @@ public class JUnit4Provider createCustomListeners( booterParameters.getProviderProperties().getProperty( "listener" ) ); jUnit4TestChecker = new JUnit4TestChecker( testClassLoader ); requestedTestMethod = booterParameters.getTestRequest().getRequestedTestMethod(); - + rerunFailingTestsCount = booterParameters.getTestRequest().getRerunFailingTestsCount(); } public RunResult invoke( Object forkTestSet ) @@ -108,7 +115,7 @@ public class JUnit4Provider final ReporterFactory reporterFactory = providerParameters.getReporterFactory(); - final RunListener reporter = reporterFactory.createReporter(); + RunListener reporter = reporterFactory.createReporter(); ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter ); @@ -121,7 +128,7 @@ public class JUnit4Provider for ( Class aTestsToRun : testsToRun ) { - executeTestSet( aTestsToRun, reporter, runNotifer ); + executeTestSet( aTestsToRun, reporter, runNotifer, null ); } runNotifer.fireTestRunFinished( result ); @@ -129,28 +136,30 @@ public class JUnit4Provider JUnit4RunListener.rethrowAnyTestMechanismFailures( result ); closeRunNotifer( jUnit4TestSetReporter, customRunListeners ); - return reporterFactory.close(); } - private void executeTestSet( Class<?> clazz, RunListener reporter, RunNotifier listeners ) + private void executeTestSet( Class<?> clazz, RunListener reporter, RunNotifier listeners, + String[] failingTestMethods ) throws ReporterException, TestSetFailedException { final ReportEntry report = new SimpleReportEntry( this.getClass().getName(), clazz.getName() ); reporter.testSetStarting( report ); + + try { if ( !StringUtils.isBlank( this.requestedTestMethod ) ) { String actualTestMethod = getMethod( clazz, this.requestedTestMethod );//add by rainLee String[] testMethods = StringUtils.split( actualTestMethod, "+" ); - execute( clazz, listeners, testMethods ); + executeWithRerun( clazz, listeners, testMethods ); } else {//the original way - execute( clazz, listeners, null ); + executeWithRerun( clazz, listeners, failingTestMethods ); } } catch ( TestSetFailedException e ) @@ -169,6 +178,34 @@ public class JUnit4Provider } } + private void executeWithRerun( Class<?> clazz, RunNotifier listeners, String[] testMethods ) + throws TestSetFailedException + { + JUnitTestFailureListener failureListener = new JUnitTestFailureListener(); + listeners.addListener( failureListener ); + + execute( clazz, listeners, testMethods ); + + // Rerun failing tests if rerunFailingTestsCount is larger than 0 + int rerunCount = this.rerunFailingTestsCount; + if ( rerunCount > 0 ) + { + for ( int i = 0; i < rerunCount; i++ ) + { + List<Failure> failures = failureListener.getAllFailures(); + if ( failures.size() == 0 ) + { + break; + } + + Set<String> methodsSet = JUnit4ProviderUtil.generateFailingTests( failureListener.getAllFailures() ); + String[] methods = methodsSet.toArray(new String[methodsSet.size()]); + failureListener.reset(); + execute( clazz, listeners, methods ); + } + } + } + private RunNotifier getRunNotifer( org.junit.runner.notification.RunListener main, Result result, List<org.junit.runner.notification.RunListener> others ) { http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java index 147a5c1..bbca2d3 100644 --- a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java +++ b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java @@ -19,11 +19,18 @@ package org.apache.maven.surefire.junit4; * under the License. */ -import java.util.Properties; +import junit.framework.TestCase; import org.apache.maven.surefire.booter.BaseProviderFactory; import org.apache.maven.surefire.testset.TestRequest; +import org.apache.maven.surefire.util.TestsToRun; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; -import junit.framework.TestCase; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; /** * @author Kristian Rosenvold @@ -33,10 +40,15 @@ public class JUnit4ProviderTest { public void testCreateProvider() { + assertNotNull( getJUnit4Provider() ); + } + + private JUnit4Provider getJUnit4Provider() + { BaseProviderFactory providerParameters = new BaseProviderFactory( null, Boolean.TRUE ); providerParameters.setProviderProperties( new Properties() ); providerParameters.setClassLoaders( this.getClass().getClassLoader() ); providerParameters.setTestRequest( new TestRequest( null, null, null ) ); - assertNotNull( new JUnit4Provider( providerParameters ) ); + return new JUnit4Provider( providerParameters ); } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java index 04f1673..8cbf0cd 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java @@ -19,12 +19,17 @@ package org.apache.maven.surefire.junitcore; * under the License. */ +import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil; import org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory; +import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener; import org.apache.maven.surefire.common.junit48.FilterFactory; import org.apache.maven.surefire.common.junit48.JUnit48Reflector; import org.apache.maven.surefire.common.junit48.JUnit48TestChecker; @@ -43,7 +48,11 @@ import org.apache.maven.surefire.util.ScanResult; import org.apache.maven.surefire.util.ScannerFilter; import org.apache.maven.surefire.util.TestsToRun; import org.apache.maven.surefire.util.internal.StringUtils; +import org.junit.internal.runners.statements.Fail; import org.junit.runner.manipulation.Filter; +import org.junit.runner.notification.Failure; + +import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.isFailureInsideJUnitItself; /** * @author Kristian Rosenvold @@ -72,6 +81,8 @@ public class JUnitCoreProvider private final ScanResult scanResult; + private final int rerunFailingTestsCount; + public JUnitCoreProvider( ProviderParameters providerParameters ) { this.providerParameters = providerParameters; @@ -81,6 +92,7 @@ public class JUnitCoreProvider this.jUnitCoreParameters = new JUnitCoreParameters( providerParameters.getProviderProperties() ); this.scannerFilter = new JUnit48TestChecker( testClassLoader ); this.requestedTestMethod = providerParameters.getTestRequest().getRequestedTestMethod(); + this.rerunFailingTestsCount = providerParameters.getTestRequest().getRerunFailingTestsCount(); customRunListeners = JUnit4RunListenerFactory.createCustomListeners( providerParameters.getProviderProperties().getProperty( "listener" ) ); @@ -131,7 +143,33 @@ public class JUnitCoreProvider org.junit.runner.notification.RunListener jUnit4RunListener = getRunListener( reporterFactory, consoleLogger ); customRunListeners.add( 0, jUnit4RunListener ); + + // Add test failure listener + JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener(); + customRunListeners.add( 0, testFailureListener ); + JUnitCoreWrapper.execute( testsToRun, jUnitCoreParameters, customRunListeners, filter ); + + // Rerun failing tests if rerunFailingTestsCount is larger than 0 + int rerunCount = this.rerunFailingTestsCount; + if ( rerunCount > 0 ) + { + for ( int i = 0; i < rerunCount; i++ ) + { + List<Failure> failures = testFailureListener.getAllFailures(); + if ( failures.size() == 0 ) + { + break; + } + Map<Class<?>, Set<String>> failingTests = + JUnit4ProviderUtil.generateFailingTests( failures, testsToRun ); + testFailureListener.reset(); + final FilterFactory filterFactory = new FilterFactory( testClassLoader ); + Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests ); + JUnitCoreWrapper.execute( testsToRun, jUnitCoreParameters, customRunListeners, + filterFactory.and( filter, failingMethodsFilter ) ); + } + } return reporterFactory.close(); } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ConcurrentRunListenerTest.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ConcurrentRunListenerTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ConcurrentRunListenerTest.java index f41554d..24fb2da 100644 --- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ConcurrentRunListenerTest.java +++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ConcurrentRunListenerTest.java @@ -338,7 +338,7 @@ public class ConcurrentRunListenerTest TestSuite suite = new TestSuite(); suite.addTest( new Junit3OddTest1( "testMe" ) ); - suite.addTest( new Junit3OddTest1( "testMe" ) ); + suite.addTest( new Junit3OddTest1( "testMe2" ) ); return suite; } @@ -361,7 +361,7 @@ public class ConcurrentRunListenerTest { TestSuite suite = new TestSuite(); - suite.addTest( new Junit3WithNestedSuite( "testMe2" ) ); + suite.addTest( new Junit3WithNestedSuite( "testMe" ) ); suite.addTest( new Junit3WithNestedSuite( "testMe2" ) ); suite.addTestSuite( Junit3Tc2.class ); return suite; @@ -388,7 +388,6 @@ public class ConcurrentRunListenerTest private void assertReporter( RunStatistics result, int success, int ignored, int failure, String message ) { assertEquals( message, success, result.getCompletedCount() ); - assertEquals( message, failure, result.getFailureSources().size() ); assertEquals( message, ignored, result.getSkipped() ); } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/ReportTestSuite.java ---------------------------------------------------------------------- diff --git a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/ReportTestSuite.java b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/ReportTestSuite.java index 2bd6513..989eda4 100644 --- a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/ReportTestSuite.java +++ b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/ReportTestSuite.java @@ -35,6 +35,8 @@ public class ReportTestSuite private int numberOfSkipped; + private int numberOfFlakes; + private Integer numberOfTests; private String name; @@ -80,6 +82,16 @@ public class ReportTestSuite this.numberOfSkipped = numberOfSkipped; } + public int getNumberOfFlakes() + { + return numberOfFlakes; + } + + public void setNumberOfFlakes( int numberOfFlakes ) + { + this.numberOfFlakes = numberOfFlakes; + } + public int getNumberOfTests() { if ( numberOfTests != null ) http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/fefaae7f/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/TestSuiteXmlParser.java ---------------------------------------------------------------------- diff --git a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/TestSuiteXmlParser.java b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/TestSuiteXmlParser.java index e54443d..72afd44 100644 --- a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/TestSuiteXmlParser.java +++ b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/TestSuiteXmlParser.java @@ -218,6 +218,10 @@ public class TestSuiteXmlParser testCase.addFailure( message != null ? message : "skipped", "skipped" ); currentSuite.setNumberOfSkipped( 1 + currentSuite.getNumberOfSkipped() ); } + else if ( "flakyFailure".equals( qName ) || "flakyError".equals( qName ) ) + { + currentSuite.setNumberOfFlakes( 1 + currentSuite.getNumberOfFlakes() ); + } else if ( "failsafe-summary".equals( qName ) ) { valid = false;