http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java index 276f3d4..b54f56c 100644 --- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java +++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java @@ -31,6 +31,10 @@ import org.junit.runner.notification.Failure; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.getAnnotatedIgnoreValue; +import static org.apache.maven.surefire.report.SimpleReportEntry.ignored; +import static org.apache.maven.surefire.report.SimpleReportEntry.withException; + /** * RunListener for JUnit4, delegates to our own RunListener * @@ -72,10 +76,8 @@ public class JUnit4RunListener public void testIgnored( Description description ) throws Exception { - final String reason = JUnit4Reflector.getAnnotatedIgnoreValue( description ); - final SimpleReportEntry report = - SimpleReportEntry.ignored( getClassName( description ), description.getDisplayName(), reason ); - reporter.testSkipped( report ); + String reason = getAnnotatedIgnoreValue( description ); + reporter.testSkipped( ignored( getClassName( description ), description.getDisplayName(), reason ) ); } /** @@ -104,33 +106,29 @@ public class JUnit4RunListener { testHeader = "Failure when constructing test"; } - ReportEntry report = SimpleReportEntry.withException( getClassName( failure.getDescription() ), testHeader, - createStackTraceWriter( failure ) ); + + ReportEntry report = + withException( getClassName( failure.getDescription() ), testHeader, createStackTraceWriter( failure ) ); if ( failure.getException() instanceof AssertionError ) { - this.reporter.testFailed( report ); + reporter.testFailed( report ); } else { - this.reporter.testError( report ); + reporter.testError( report ); } - failureFlag.set( true ); - } - protected StackTraceWriter createStackTraceWriter( Failure failure ) - { - return new JUnit4StackTraceWriter( failure ); + failureFlag.set( true ); } @SuppressWarnings( { "UnusedDeclaration" } ) public void testAssumptionFailure( Failure failure ) { - this.reporter.testAssumptionFailure( createReportEntry( failure.getDescription() ) ); + reporter.testAssumptionFailure( createReportEntry( failure.getDescription() ) ); failureFlag.set( true ); } - /** * Called after a specific test has finished. * @@ -146,12 +144,15 @@ public class JUnit4RunListener } } - protected SimpleReportEntry createReportEntry( Description description ) + /** + * Delegates to {@link RunListener#testExecutionSkippedByUser()}. + */ + public void testExecutionSkippedByUser() { - return new SimpleReportEntry( getClassName( description ), description.getDisplayName() ); + reporter.testExecutionSkippedByUser(); } - public String getClassName( Description description ) + private static String getClassName( Description description ) { String name = extractClassName( description ); if ( name == null || isInsaneJunitNullString( name ) ) @@ -170,34 +171,30 @@ public class JUnit4RunListener return name; } - private boolean isInsaneJunitNullString( String value ) + protected StackTraceWriter createStackTraceWriter( Failure failure ) { - return "null".equals( value ); + return new JUnit4StackTraceWriter( failure ); + } + + protected SimpleReportEntry createReportEntry( Description description ) + { + return new SimpleReportEntry( getClassName( description ), description.getDisplayName() ); } public static String extractClassName( Description description ) { String displayName = description.getDisplayName(); Matcher m = PARENS.matcher( displayName ); - if ( !m.find() ) - { - return displayName; - } - return m.group( 1 ); + return m.find() ? m.group( 1 ) : displayName; } public static String extractMethodName( Description description ) { String displayName = description.getDisplayName(); int i = displayName.indexOf( "(" ); - if ( i >= 0 ) - { - return displayName.substring( 0, i ); - } - return displayName; + return i >= 0 ? displayName.substring( 0, i ) : displayName; } - public static void rethrowAnyTestMechanismFailures( Result run ) throws TestSetFailedException { @@ -214,4 +211,9 @@ public class JUnit4RunListener } } } + + private static boolean isInsaneJunitNullString( String value ) + { + return "null".equals( value ); + } }
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java new file mode 100644 index 0000000..e9136e1 --- /dev/null +++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java @@ -0,0 +1,106 @@ +package org.apache.maven.surefire.common.junit4; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +/** + * Extends {@link RunNotifier JUnit notifier}, + * encapsulates several different types of {@link RunListener JUnit listeners}, and + * fires events to listeners. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +public class Notifier + extends RunNotifier +{ + private final Collection<RunListener> listeners = new ArrayList<RunListener>(); + + private JUnit4RunListener reporter; + + @Override + public void pleaseStop() + { + super.pleaseStop(); + reporter.testExecutionSkippedByUser(); + } + + /** + * Adds reporter listener to the bottom of queue and retrieves old reporter if any exists. + * + * @param reporter registered listener + * @return old listener; or null if did not exist + */ + public JUnit4RunListener setReporter( JUnit4RunListener reporter ) + { + JUnit4RunListener old = this.reporter; + this.reporter = reporter; + addListener( reporter ); + return old; + } + + @Override + public void addListener( RunListener listener ) + { + listeners.add( listener ); + super.addListener( listener ); + } + + public Notifier addListeners( Collection<RunListener> given ) + { + for ( RunListener listener : given ) + { + addListener( listener ); + } + return this; + } + + public Notifier addListeners( RunListener... given ) + { + for ( RunListener listener : given ) + { + addListener( listener ); + } + return this; + } + + @Override + public void removeListener( RunListener listener ) + { + listeners.remove( listener ); + super.removeListener( listener ); + } + + public void removeListeners() + { + for ( Iterator<RunListener> it = listeners.iterator(); it.hasNext(); ) + { + RunListener listener = it.next(); + it.remove(); + super.removeListener( listener ); + } + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java index 04484e0..99d7aae 100644 --- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java +++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java @@ -26,7 +26,7 @@ import org.apache.maven.surefire.report.ReportEntry; import org.apache.maven.surefire.report.RunListener; /** - * Internal use only + * Internal tests use only. */ public class MockReporter implements RunListener @@ -83,6 +83,15 @@ public class MockReporter testIgnored.incrementAndGet(); } + public void testExecutionSkippedByUser() + { + } + + public void testSkippedByUser( ReportEntry report ) + { + testSkipped( report ); + } + public int getTestSucceeded() { return testSucceeded.get(); http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector40Test.java ---------------------------------------------------------------------- diff --git a/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector40Test.java b/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector40Test.java index 28b5fed..df4819c 100644 --- a/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector40Test.java +++ b/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector40Test.java @@ -47,6 +47,34 @@ public class JUnit4Reflector40Test { } } + + public void testCreateIgnored() + { + Ignore ignore = JUnit4Reflector.createIgnored( "error" ); + assertNotNull( ignore ); + assertNotNull( ignore.value() ); + assertEquals( "error", ignore.value() ); + } + + public void testCreateDescription() + { + Ignore ignore = JUnit4Reflector.createIgnored( "error" ); + Description description = JUnit4Reflector.createDescription( "exception", ignore ); + assertEquals( "exception", description.getDisplayName() ); + assertEquals( "exception", description.toString() ); + assertEquals( 0, description.getChildren().size() ); + // JUnit 4 description does not get annotations + Ignore annotatedIgnore = JUnit4Reflector.getAnnotatedIgnore( description ); + assertNull( annotatedIgnore ); + } + + public void testCreatePureDescription() + { + Description description = JUnit4Reflector.createDescription( "exception" ); + assertEquals( "exception", description.getDisplayName() ); + assertEquals( "exception", description.toString() ); + assertEquals( 0, description.getChildren().size() ); + } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java index aac3655..9ca397e 100644 --- a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java +++ b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java @@ -100,6 +100,15 @@ public class JUnitTestSetTest throw new IllegalStateException(); } + public void testExecutionSkippedByUser() + { + } + + public void testSkippedByUser( ReportEntry report ) + { + testSkipped( report ); + } + public List getSucceededTests() { return succeededTests; http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4FailFastListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4FailFastListener.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4FailFastListener.java new file mode 100644 index 0000000..d45b678 --- /dev/null +++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4FailFastListener.java @@ -0,0 +1,48 @@ +package org.apache.maven.surefire.junit4; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +/** + * Calling {@link RunNotifier#pleaseStop()} if failure appeared. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +final class JUnit4FailFastListener + extends RunListener +{ + private final RunNotifier notifier; + + JUnit4FailFastListener( RunNotifier notifier ) + { + this.notifier = notifier; + } + + @Override + public void testFailure( Failure failure ) + throws Exception + { + notifier.pleaseStop(); + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/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 3f0e57f..e8f041d 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,22 +19,20 @@ package org.apache.maven.surefire.junit4; * under the License. */ -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Set; +import org.apache.maven.surefire.booter.Command; +import org.apache.maven.surefire.booter.MasterProcessListener; +import org.apache.maven.surefire.booter.MasterProcessReader; import org.apache.maven.surefire.common.junit4.ClassMethod; -import org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil; -import org.apache.maven.surefire.common.junit4.JUnit4Reflector; 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.common.junit4.Notifier; import org.apache.maven.surefire.providerapi.AbstractProvider; import org.apache.maven.surefire.providerapi.ProviderParameters; -import org.apache.maven.surefire.report.ConsoleOutputCapture; import org.apache.maven.surefire.report.ConsoleOutputReceiver; import org.apache.maven.surefire.report.PojoStackTraceWriter; import org.apache.maven.surefire.report.ReportEntry; @@ -49,13 +47,28 @@ import org.apache.maven.surefire.util.RunOrderCalculator; import org.apache.maven.surefire.util.ScanResult; import org.apache.maven.surefire.util.TestsToRun; import org.junit.runner.Description; -import org.junit.runner.Request; import org.junit.runner.Result; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; -import org.junit.runner.notification.RunNotifier; - +import org.junit.runner.notification.StoppedByUserException; + +import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST; +import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.createSuiteDescription; +import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.cutTestClassAndMethod; +import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests; +import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createDescription; +import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createIgnored; +import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures; +import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners; +import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture; +import static org.apache.maven.surefire.report.SimpleReportEntry.withException; import static org.apache.maven.surefire.testset.TestListResolver.toClassFileName; +import static org.apache.maven.surefire.util.TestsToRun.fromClass; +import static org.junit.runner.Request.aClass; +import static org.junit.runner.Request.method; +import static java.lang.reflect.Modifier.isAbstract; +import static java.lang.reflect.Modifier.isInterface; +import static java.util.Collections.unmodifiableCollection; /** * @author Kristian Rosenvold @@ -67,7 +80,7 @@ public class JUnit4Provider private final ClassLoader testClassLoader; - private final List<org.junit.runner.notification.RunListener> customRunListeners; + private final Collection<org.junit.runner.notification.RunListener> customRunListeners; private final JUnit4TestChecker jUnit4TestChecker; @@ -81,16 +94,20 @@ public class JUnit4Provider private final int rerunFailingTestsCount; + private final MasterProcessReader commandsReader; + private TestsToRun testsToRun; public JUnit4Provider( ProviderParameters booterParameters ) { + // don't start a thread in MasterProcessReader while we are in in-plugin process + commandsReader = booterParameters.isInsideFork() ? MasterProcessReader.getReader() : null; providerParameters = booterParameters; testClassLoader = booterParameters.getTestClassLoader(); scanResult = booterParameters.getScanResult(); runOrderCalculator = booterParameters.getRunOrderCalculator(); String listeners = booterParameters.getProviderProperties().get( "listener" ); - customRunListeners = JUnit4RunListenerFactory.createCustomListeners( listeners ); + customRunListeners = unmodifiableCollection( createCustomListeners( listeners ) ); jUnit4TestChecker = new JUnit4TestChecker( testClassLoader ); TestRequest testRequest = booterParameters.getTestRequest(); testResolver = testRequest.getTestListResolver(); @@ -100,6 +117,11 @@ public class JUnit4Provider public RunResult invoke( Object forkTestSet ) throws TestSetFailedException { + if ( isRerunFailingTests() && isFailFast() ) + { + throw new TestSetFailedException( "don't enable parameters rerunFailingTestsCount, skipAfterFailureCount" ); + } + if ( testsToRun == null ) { if ( forkTestSet instanceof TestsToRun ) @@ -108,7 +130,7 @@ public class JUnit4Provider } else if ( forkTestSet instanceof Class ) { - testsToRun = TestsToRun.fromClass( (Class) forkTestSet ); + testsToRun = fromClass( (Class) forkTestSet ); } else { @@ -118,48 +140,102 @@ public class JUnit4Provider upgradeCheck(); - final ReporterFactory reporterFactory = providerParameters.getReporterFactory(); + ReporterFactory reporterFactory = providerParameters.getReporterFactory(); RunListener reporter = reporterFactory.createReporter(); - ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter ); - - JUnit4RunListener jUnit4TestSetReporter = new JUnit4RunListener( reporter ); + startCapture( (ConsoleOutputReceiver) reporter ); + Notifier notifier = new Notifier(); + notifier.setReporter( new JUnit4RunListener( reporter ) ); + if ( isFailFast() ) + { + notifier.addListener( new JUnit4FailFastListener( notifier ) ); + } Result result = new Result(); - RunNotifier runNotifier = getRunNotifier( jUnit4TestSetReporter, result, customRunListeners ); - - runNotifier.fireTestRunStarted( testsToRun.allowEagerReading() - ? createTestsDescription() - : JUnit4Reflector.createDescription( UNDETERMINED_TESTS_DESCRIPTION ) ); + notifier.addListeners( customRunListeners ) + .addListener( result.createListener() ); - for ( Class aTestsToRun : testsToRun ) + if ( isFailFast() && commandsReader != null ) { - executeTestSet( aTestsToRun, reporter, runNotifier ); + registerPleaseStopJunitListener( notifier ); } - runNotifier.fireTestRunFinished( result ); + try + { + notifier.fireTestRunStarted( testsToRun.allowEagerReading() + ? createTestsDescription() + : createDescription( UNDETERMINED_TESTS_DESCRIPTION ) ); - JUnit4RunListener.rethrowAnyTestMechanismFailures( result ); + for ( Class aTestsToRun : testsToRun ) + { + executeTestSet( aTestsToRun, reporter, notifier ); + } + } + finally + { + notifier.fireTestRunFinished( result ); + notifier.removeListeners(); + closeCommandsReader(); + } - closeRunNotifier( jUnit4TestSetReporter, customRunListeners ); + rethrowAnyTestMechanismFailures( result ); return reporterFactory.close(); } - private void executeTestSet( Class<?> clazz, RunListener reporter, RunNotifier listeners ) + private boolean isRerunFailingTests() + { + return rerunFailingTestsCount > 0; + } + + private boolean isFailFast() + { + return providerParameters.getSkipAfterFailureCount() > 0; + } + + private void closeCommandsReader() + { + if ( commandsReader != null ) + { + commandsReader.stop(); + } + } + + private MasterProcessListener registerPleaseStopJunitListener( final Notifier notifier ) + { + MasterProcessListener listener = new MasterProcessListener() + { + public void update( Command command ) + { + notifier.pleaseStop(); + } + }; + commandsReader.addListener( SKIP_SINCE_NEXT_TEST, listener ); + return listener; + } + + private void executeTestSet( Class<?> clazz, RunListener reporter, Notifier notifier ) { final ReportEntry report = new SimpleReportEntry( getClass().getName(), clazz.getName() ); reporter.testSetStarting( report ); try { - executeWithRerun( clazz, listeners ); + executeWithRerun( clazz, notifier ); } catch ( Throwable e ) { - String reportName = report.getName(); - String reportSourceName = report.getSourceName(); - PojoStackTraceWriter stackWriter = new PojoStackTraceWriter( reportSourceName, reportName, e ); - reporter.testError( SimpleReportEntry.withException( reportSourceName, reportName, stackWriter ) ); + if ( isFailFast() && e instanceof StoppedByUserException ) + { + String reason = e.getClass().getName(); + notifier.fireTestIgnored( createDescription( clazz.getName(), createIgnored( reason ) ) ); + } + else + { + String reportName = report.getName(); + String reportSourceName = report.getSourceName(); + PojoStackTraceWriter stackWriter = new PojoStackTraceWriter( reportSourceName, reportName, e ); + reporter.testError( withException( reportSourceName, reportName, stackWriter ) ); + } } finally { @@ -167,55 +243,28 @@ public class JUnit4Provider } } - private void executeWithRerun( Class<?> clazz, RunNotifier listeners ) throws TestSetFailedException + private void executeWithRerun( Class<?> clazz, Notifier notifier ) throws TestSetFailedException { JUnitTestFailureListener failureListener = new JUnitTestFailureListener(); - listeners.addListener( failureListener ); + notifier.addListener( failureListener ); boolean hasMethodFilter = testResolver != null && testResolver.hasMethodPatterns(); - execute( clazz, listeners, hasMethodFilter ? new TestResolverFilter() : new NullFilter() ); + execute( clazz, notifier, hasMethodFilter ? new TestResolverFilter() : new NullFilter() ); // Rerun failing tests if rerunFailingTestsCount is larger than 0 - if ( rerunFailingTestsCount > 0 ) + if ( isRerunFailingTests() ) { for ( int i = 0; i < rerunFailingTestsCount && !failureListener.getAllFailures().isEmpty(); i++ ) { - Set<ClassMethod> failedTests = - JUnit4ProviderUtil.generateFailingTests( failureListener.getAllFailures() ); + Set<ClassMethod> failedTests = generateFailingTests( failureListener.getAllFailures() ); failureListener.reset(); if ( !failedTests.isEmpty() ) { - executeFailedMethod( listeners, failedTests ); + executeFailedMethod( notifier, failedTests ); } } } } - private static RunNotifier getRunNotifier( org.junit.runner.notification.RunListener main, Result result, - List<org.junit.runner.notification.RunListener> others ) - { - RunNotifier notifier = new RunNotifier(); - notifier.addListener( main ); - notifier.addListener( result.createListener() ); - for ( org.junit.runner.notification.RunListener listener : others ) - { - notifier.addListener( listener ); - } - return notifier; - } - - // I am not entirely sure as to why we do this explicit freeing, it's one of those - // pieces of code that just seem to linger on in here ;) - private static void closeRunNotifier( org.junit.runner.notification.RunListener main, - Iterable<org.junit.runner.notification.RunListener> others ) - { - RunNotifier notifier = new RunNotifier(); - notifier.removeListener( main ); - for ( org.junit.runner.notification.RunListener listener : others ) - { - notifier.removeListener( listener ); - } - } - public Iterable<Class<?>> getSuites() { testsToRun = scanClassPath(); @@ -258,7 +307,7 @@ public class JUnit4Provider { classes.add( clazz ); } - return JUnit4ProviderUtil.createSuiteDescription( classes ); + return createSuiteDescription( classes ); } private static boolean isJUnit4UpgradeCheck() @@ -266,12 +315,12 @@ public class JUnit4Provider return System.getProperty( "surefire.junit4.upgradecheck" ) != null; } - private static void execute( Class<?> testClass, RunNotifier notifier, Filter filter ) + private static void execute( Class<?> testClass, Notifier notifier, Filter filter ) { final int classModifiers = testClass.getModifiers(); - if ( !Modifier.isAbstract( classModifiers ) && !Modifier.isInterface( classModifiers ) ) + if ( !isAbstract( classModifiers ) && !isInterface( classModifiers ) ) { - Runner runner = Request.aClass( testClass ).filterWith( filter ).getRunner(); + Runner runner = aClass( testClass ).filterWith( filter ).getRunner(); if ( countTestsInRunner( runner.getDescription() ) != 0 ) { runner.run( notifier ); @@ -279,7 +328,7 @@ public class JUnit4Provider } } - private void executeFailedMethod( RunNotifier notifier, Set<ClassMethod> failedMethods ) + private void executeFailedMethod( Notifier notifier, Set<ClassMethod> failedMethods ) throws TestSetFailedException { for ( ClassMethod failedMethod : failedMethods ) @@ -288,7 +337,7 @@ public class JUnit4Provider { Class<?> methodClass = Class.forName( failedMethod.getClazz(), true, testClassLoader ); String methodName = failedMethod.getMethod(); - Request.method( methodClass, methodName ).getRunner().run( notifier ); + method( methodClass, methodName ).getRunner().run( notifier ); } catch ( ClassNotFoundException e ) { @@ -353,7 +402,7 @@ public class JUnit4Provider public boolean shouldRun( Description description ) { // class: Java class name; method: 1. "testMethod" or 2. "testMethod[5+whatever]" in @Parameterized - final ClassMethod cm = JUnit4ProviderUtil.cutTestClassAndMethod( description ); + final ClassMethod cm = cutTestClassAndMethod( description ); final boolean isSuite = description.isSuite(); final boolean isValidTest = description.isTest() && cm.isValid(); final String clazz = cm.getClazz(); http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java index 7254364..5886317 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java @@ -113,6 +113,12 @@ public abstract class ConcurrentRunListener testMethod.detachFromCurrentThread(); } + public void testExecutionSkippedByUser() + { + // cannot guarantee proper call to all listeners + reporterManagerThreadLocal.get().testExecutionSkippedByUser(); + } + public void testAssumptionFailure( ReportEntry failure ) { final TestMethod testMethod = getOrCreateThreadAttachedTestMethod( failure ); @@ -180,19 +186,15 @@ public abstract class ConcurrentRunListener return reporterManagerThreadLocal.get(); } - public static ConcurrentRunListener createInstance( Map<String, TestSet> classMethodCounts, - ReporterFactory reporterManagerFactory, + ReporterFactory reporterFactory, boolean parallelClasses, boolean parallelBoth, ConsoleLogger consoleLogger ) throws TestSetFailedException { - if ( parallelClasses ) - { - return new ClassesParallelRunListener( classMethodCounts, reporterManagerFactory, consoleLogger ); - } - return new MethodsParallelRunListener( classMethodCounts, reporterManagerFactory, !parallelBoth, - consoleLogger ); + return parallelClasses + ? new ClassesParallelRunListener( classMethodCounts, reporterFactory, consoleLogger ) + : new MethodsParallelRunListener( classMethodCounts, reporterFactory, !parallelBoth, consoleLogger ); } @@ -210,5 +212,4 @@ public abstract class ConcurrentRunListener consoleLogger.info( new String( buf, off, len ) ); } } - } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/FilteringRequest.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/FilteringRequest.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/FilteringRequest.java new file mode 100644 index 0000000..5e1c192 --- /dev/null +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/FilteringRequest.java @@ -0,0 +1,54 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.NoTestsRemainException; + +/** + * Moved nested class from {@link JUnitCoreWrapper}. + */ +final class FilteringRequest + extends Request +{ + private Runner filteredRunner; + + public FilteringRequest( Request req, Filter filter ) + { + try + { + Runner runner = req.getRunner(); + filter.apply( runner ); + filteredRunner = runner; + } + catch ( NoTestsRemainException e ) + { + filteredRunner = null; + } + } + + @Override + public Runner getRunner() + { + return filteredRunner; + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnit47FailFastListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnit47FailFastListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnit47FailFastListener.java new file mode 100644 index 0000000..dda6b68 --- /dev/null +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnit47FailFastListener.java @@ -0,0 +1,65 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Calling {@link Stoppable#pleaseStop()} if failure appeared. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +final class JUnit47FailFastListener + extends RunListener +{ + private final Stoppable stoppable; + + private final ConcurrentLinkedQueue<String> testClassNames = new ConcurrentLinkedQueue<String>(); + + JUnit47FailFastListener( Stoppable stoppable ) + { + this.stoppable = stoppable; + } + + Queue<String> getRemainingTestClasses() + { + return testClassNames; + } + + @Override + public void testStarted( Description description ) + throws Exception + { + testClassNames.remove( description.getClassName() ); + } + + @Override + public void testFailure( Failure failure ) + throws Exception + { + stoppable.pleaseStop(); + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCore.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCore.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCore.java new file mode 100644 index 0000000..7f1a03a --- /dev/null +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCore.java @@ -0,0 +1,90 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.surefire.common.junit4.Notifier; +import org.apache.maven.surefire.testset.TestSetFailedException; +import org.junit.runner.Result; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunListener; + +/** + * JUnitCore solves bugs in original junit class {@link org.junit.runner.JUnitCore}.<p> + * The notifier method {@link org.junit.runner.notification.RunNotifier#fireTestRunFinished} + * is called anyway in finally block. + * This class provides method {@link #pleaseStop()} without any need to retrieve + * {@link org.junit.runner.notification.RunNotifier} outside. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + * @see https://github.com/junit-team/junit/issues/1186 + */ +class JUnitCore + implements Stoppable +{ + private final Notifier notifier; + + JUnitCore( Notifier notifier ) + { + this.notifier = notifier; + } + + Result run( Runner runner ) + throws TestSetFailedException + { + Result result = new Result(); + RunListener listener = result.createListener(); + notifier.addFirstListener( listener ); + try + { + notifier.fireTestRunStarted( runner.getDescription() ); + runner.run( notifier ); + } + catch ( Throwable e ) + { + afterException( e ); + } + finally + { + notifier.fireTestRunFinished( result ); + notifier.removeListener( listener ); + afterFinished(); + } + return result; + } + + protected void afterException( Throwable e ) + throws TestSetFailedException + { + throw new TestSetFailedException( e ); + } + + protected void afterFinished() + { + } + + /** + * {@inheritDoc} + */ + public void pleaseStop() + { + notifier.pleaseStop(); + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/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 43b8a1e..243cca0 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,14 +19,18 @@ package org.apache.maven.surefire.junitcore; * under the License. */ +import java.util.Collection; 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.booter.Command; +import org.apache.maven.surefire.booter.MasterProcessListener; +import org.apache.maven.surefire.booter.MasterProcessReader; +import org.apache.maven.surefire.common.junit4.JUnit4RunListener; import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener; +import org.apache.maven.surefire.common.junit4.Notifier; import org.apache.maven.surefire.common.junit48.FilterFactory; import org.apache.maven.surefire.common.junit48.JUnit48Reflector; import org.apache.maven.surefire.common.junit48.JUnit48TestChecker; @@ -34,9 +38,7 @@ import org.apache.maven.surefire.providerapi.AbstractProvider; import org.apache.maven.surefire.providerapi.ProviderParameters; import org.apache.maven.surefire.report.ConsoleLogger; import org.apache.maven.surefire.report.ConsoleOutputCapture; -import org.apache.maven.surefire.report.ConsoleOutputReceiver; import org.apache.maven.surefire.report.ReporterFactory; -import org.apache.maven.surefire.report.RunListener; import org.apache.maven.surefire.suite.RunResult; import org.apache.maven.surefire.testset.TestListResolver; import org.apache.maven.surefire.testset.TestSetFailedException; @@ -45,6 +47,14 @@ import org.apache.maven.surefire.util.ScanResult; import org.apache.maven.surefire.util.ScannerFilter; import org.apache.maven.surefire.util.TestsToRun; import org.junit.runner.manipulation.Filter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST; +import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance; +import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests; +import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners; +import static java.util.Collections.unmodifiableCollection; /** * @author Kristian Rosenvold @@ -59,7 +69,7 @@ public class JUnitCoreProvider private final ScannerFilter scannerFilter; - private final List<org.junit.runner.notification.RunListener> customRunListeners; + private final Collection<RunListener> customRunListeners; private final ProviderParameters providerParameters; @@ -67,16 +77,19 @@ public class JUnitCoreProvider private final int rerunFailingTestsCount; - private TestsToRun testsToRun; - private final JUnit48Reflector jUnit48Reflector; private final RunOrderCalculator runOrderCalculator; private final TestListResolver testResolver; + private final MasterProcessReader commandsReader; + + private TestsToRun testsToRun; + public JUnitCoreProvider( ProviderParameters providerParameters ) { + commandsReader = providerParameters.isInsideFork() ? MasterProcessReader.getReader() : null; this.providerParameters = providerParameters; testClassLoader = providerParameters.getTestClassLoader(); scanResult = providerParameters.getScanResult(); @@ -85,8 +98,8 @@ public class JUnitCoreProvider scannerFilter = new JUnit48TestChecker( testClassLoader ); testResolver = providerParameters.getTestRequest().getTestListResolver(); rerunFailingTestsCount = providerParameters.getTestRequest().getRerunFailingTestsCount(); - customRunListeners = JUnit4RunListenerFactory.createCustomListeners( - providerParameters.getProviderProperties().get( "listener" ) ); + String listeners = providerParameters.getProviderProperties().get( "listener" ); + customRunListeners = unmodifiableCollection( createCustomListeners( listeners ) ); jUnit48Reflector = new JUnit48Reflector( testClassLoader ); } @@ -104,6 +117,11 @@ public class JUnitCoreProvider public RunResult invoke( Object forkTestSet ) throws TestSetFailedException { + if ( isRerunFailingTests() && isFailFast() ) + { + throw new TestSetFailedException( "don't enable parameters rerunFailingTestsCount, skipAfterFailureCount" ); + } + final ReporterFactory reporterFactory = providerParameters.getReporterFactory(); final ConsoleLogger consoleLogger = providerParameters.getConsoleLogger(); @@ -127,55 +145,96 @@ public class JUnitCoreProvider } } - customRunListeners.add( 0, getRunListener( reporterFactory, consoleLogger ) ); + Notifier notifier = new Notifier(); + notifier.setReporter( createRunListener( reporterFactory, consoleLogger ) ); // Add test failure listener JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener(); - customRunListeners.add( 0, testFailureListener ); + notifier.addListener( testFailureListener ); - JUnitCoreWrapper.execute( consoleLogger, testsToRun, jUnitCoreParameters, customRunListeners, filter ); + if ( isFailFast() && commandsReader != null ) + { + registerPleaseStopJunitListener( notifier ); + } - // Rerun failing tests if rerunFailingTestsCount is larger than 0 - if ( rerunFailingTestsCount > 0 ) + try { - for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ ) + JUnitCoreWrapper core = new JUnitCoreWrapper( notifier, jUnitCoreParameters, consoleLogger, isFailFast() ); + + core.execute( testsToRun, customRunListeners, filter ); + + // Rerun failing tests if rerunFailingTestsCount is larger than 0 + if ( isRerunFailingTests() ) { - Map<Class<?>, Set<String>> failingTests = - JUnit4ProviderUtil.generateFailingTests( testFailureListener.getAllFailures(), testClassLoader ); - testFailureListener.reset(); - final FilterFactory filterFactory = new FilterFactory( testClassLoader ); - Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests ); - JUnitCoreWrapper.execute( consoleLogger, testsToRun, jUnitCoreParameters, customRunListeners, - failingMethodsFilter ); + for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ ) + { + List<Failure> failures = testFailureListener.getAllFailures(); + Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader ); + testFailureListener.reset(); + final FilterFactory filterFactory = new FilterFactory( testClassLoader ); + Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests ); + core.execute( testsToRun, failingMethodsFilter ); + } } } + finally + { + notifier.removeListeners(); + closeCommandsReader(); + } return reporterFactory.close(); } - private org.junit.runner.notification.RunListener getRunListener( ReporterFactory reporterFactory, - ConsoleLogger consoleLogger ) + private boolean isRerunFailingTests() + { + return rerunFailingTestsCount > 0; + } + + private boolean isFailFast() + { + return providerParameters.getSkipAfterFailureCount() > 0; + } + + private void closeCommandsReader() + { + if ( commandsReader != null ) + { + commandsReader.stop(); + } + } + + private MasterProcessListener registerPleaseStopJunitListener( final Notifier stoppable ) + { + MasterProcessListener listener = new MasterProcessListener() + { + public void update( Command command ) + { + stoppable.pleaseStop(); + } + }; + commandsReader.addListener( SKIP_SINCE_NEXT_TEST, listener ); + return listener; + } + + private JUnit4RunListener createRunListener( ReporterFactory reporterFactory, ConsoleLogger consoleLogger ) throws TestSetFailedException { - org.junit.runner.notification.RunListener jUnit4RunListener; if ( isSingleThreaded() ) { NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() ); ConsoleOutputCapture.startCapture( rm ); - jUnit4RunListener = rm; + return rm; } else { final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>(); - RunListener listener = - ConcurrentRunListener.createInstance( testSetMap, reporterFactory, - isParallelTypes(), - isParallelMethodsAndTypes(), consoleLogger ); - ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) listener ); + ConcurrentRunListener listener = createInstance( testSetMap, reporterFactory, isParallelTypes(), + isParallelMethodsAndTypes(), consoleLogger ); + ConsoleOutputCapture.startCapture( listener ); - jUnit4RunListener = new JUnitCoreRunListener( listener, testSetMap ); + return new JUnitCoreRunListener( listener, testSetMap ); } - return jUnit4RunListener; } private boolean isParallelMethodsAndTypes() http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java index bf2f71a..e0c9f9e 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java @@ -19,79 +19,103 @@ package org.apache.maven.surefire.junitcore; * under the License. */ -import org.apache.maven.surefire.common.junit4.JUnit4RunListener; +import org.apache.maven.surefire.common.junit4.Notifier; import org.apache.maven.surefire.junitcore.pc.ParallelComputer; import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder; import org.apache.maven.surefire.report.ConsoleLogger; import org.apache.maven.surefire.testset.TestSetFailedException; import org.apache.maven.surefire.util.TestsToRun; +import org.junit.Ignore; import org.junit.runner.Computer; -import org.junit.runner.JUnitCore; import org.junit.runner.Request; import org.junit.runner.Result; -import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; -import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.StoppedByUserException; -import java.util.List; +import java.util.Collection; +import java.util.Collections; +import java.util.Queue; +import java.util.Random; + +import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createDescription; +import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createIgnored; +import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures; /** * Encapsulates access to JUnitCore * * @author Kristian Rosenvold */ - -class JUnitCoreWrapper +final class JUnitCoreWrapper { - public static void execute( ConsoleLogger logger, TestsToRun testsToRun, JUnitCoreParameters jUnitCoreParameters, - List<RunListener> listeners, Filter filter ) + private final Notifier notifier; + private final JUnitCoreParameters jUnitCoreParameters; + private final ConsoleLogger logger; + private final boolean failFast; + + private Object o = new Random().nextInt(); + + JUnitCoreWrapper( Notifier notifier, JUnitCoreParameters jUnitCoreParameters, ConsoleLogger logger, + boolean failFast ) + { + this.notifier = notifier; + this.jUnitCoreParameters = jUnitCoreParameters; + this.logger = logger; + this.failFast = failFast; + } + + void execute( TestsToRun testsToRun, Filter filter ) + throws TestSetFailedException + { + execute( testsToRun, Collections.<RunListener>emptyList(), filter ); + } + + void execute( TestsToRun testsToRun, Collection<RunListener> listeners, Filter filter ) throws TestSetFailedException { - JUnitCore junitCore = createJUnitCore( listeners ); if ( testsToRun.allowEagerReading() ) { - executeEager( logger, testsToRun, filter, jUnitCoreParameters, junitCore ); + executeEager( testsToRun, filter, listeners ); } else { - executeLazy( logger, testsToRun, filter, jUnitCoreParameters, junitCore ); + executeLazy( testsToRun, filter, listeners ); } } - private static JUnitCore createJUnitCore( List<RunListener> listeners ) + private JUnitCore createJUnitCore( final Notifier notifier, Collection<RunListener> listeners ) { - JUnitCore junitCore = new JUnitCore(); - for ( RunListener runListener : listeners ) - { - junitCore.addListener( runListener ); - } + JUnitCore junitCore = new JUnitCore( notifier ); + + // custom listeners added last + notifier.addListeners( listeners ); + return junitCore; } - private static void executeEager( ConsoleLogger logger, TestsToRun testsToRun, Filter filter, - JUnitCoreParameters jUnitCoreParameters, JUnitCore junitCore ) + private void executeEager( TestsToRun testsToRun, Filter filter, Collection<RunListener> listeners ) throws TestSetFailedException { + JUnitCore junitCore = createJUnitCore( notifier, listeners ); Class<?>[] tests = testsToRun.getLocatedClasses(); - Computer computer = createComputer( logger, jUnitCoreParameters ); - createRequestAndRun( filter, computer, junitCore, tests ); + Computer computer = createComputer(); + createRequestAndRun( filter, computer, junitCore.withReportedTests( tests ), tests ); } - private static void executeLazy( ConsoleLogger logger, TestsToRun testsToRun, Filter filter, - JUnitCoreParameters jUnitCoreParameters, JUnitCore junitCore ) + private void executeLazy( TestsToRun testsToRun, Filter filter, Collection<RunListener> listeners ) throws TestSetFailedException { + JUnitCore junitCore = createJUnitCore( notifier, listeners ); // in order to support LazyTestsToRun, the iterator must be used - for ( Class clazz : testsToRun ) + for ( Class<?> clazz : testsToRun ) { - Computer computer = createComputer( logger, jUnitCoreParameters ); - createRequestAndRun( filter, computer, junitCore, clazz ); + Computer computer = createComputer(); + createRequestAndRun( filter, computer, junitCore.withReportedTests( clazz ), clazz ); } } - private static void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, - Class<?>... classesToRun ) + private void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, Class<?>... classesToRun ) throws TestSetFailedException { Request req = Request.classes( computer, classesToRun ); @@ -105,8 +129,8 @@ class JUnitCoreWrapper } } - Result run = junitCore.run( req ); - JUnit4RunListener.rethrowAnyTestMechanismFailures( run ); + Result run = junitCore.run( req.getRunner() ); + rethrowAnyTestMechanismFailures( run ); if ( computer instanceof ParallelComputer ) { @@ -118,37 +142,78 @@ class JUnitCoreWrapper } } - private static Computer createComputer( ConsoleLogger logger, JUnitCoreParameters parameters ) - throws TestSetFailedException + private Computer createComputer() { - return parameters.isNoThreading() + return jUnitCoreParameters.isNoThreading() ? Computer.serial() - : new ParallelComputerBuilder( logger, parameters ).buildComputer(); + : new ParallelComputerBuilder( logger, jUnitCoreParameters ).buildComputer(); } - private static class FilteringRequest - extends Request + private final class JUnitCore + extends org.apache.maven.surefire.junitcore.JUnitCore { - private Runner filteredRunner; + private final JUnit47FailFastListener failFastListener; - public FilteringRequest( Request req, Filter filter ) + JUnitCore( Notifier notifier ) { - try + super( notifier ); + failFastListener = failFast ? new JUnit47FailFastListener( this ) : null; + if ( failFastListener != null ) { - Runner runner = req.getRunner(); - filter.apply( runner ); - filteredRunner = runner; + notifier.addListener( failFastListener ); } - catch ( NoTestsRemainException e ) + } + + JUnitCore withReportedTests( Class<?>... tests ) + { + Queue<String> stoppedTests = getRemainingTestClasses(); + if ( stoppedTests != null ) + { + for ( Class<?> test : tests ) + { + stoppedTests.add( test.getName() ); + } + } + return this; + } + + @Override + @SuppressWarnings( "checkstyle:innerassignment" ) + protected void afterException( Throwable e ) + throws TestSetFailedException + { + if ( failFast && e instanceof StoppedByUserException ) + { + Queue<String> stoppedTests = getRemainingTestClasses(); + if ( stoppedTests != null ) + { + String reason = e.getClass().getName(); + Ignore reasonForIgnoredTest = createIgnored( reason ); + for ( String clazz; ( clazz = stoppedTests.poll() ) != null; ) + { + notifier.fireTestIgnored( createDescription( clazz, reasonForIgnoredTest ) ); + } + } + } + else { - filteredRunner = null; + super.afterException( e ); } } @Override - public Runner getRunner() + protected void afterFinished() + { + Queue<String> stoppedTests = getRemainingTestClasses(); + if ( stoppedTests != null ) + { + stoppedTests.clear(); + } + } + + private Queue<String> getRemainingTestClasses() { - return filteredRunner; + return failFastListener == null ? null : failFastListener.getRemainingTestClasses(); } } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/Stoppable.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/Stoppable.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/Stoppable.java new file mode 100644 index 0000000..2450e64 --- /dev/null +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/Stoppable.java @@ -0,0 +1,32 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +interface Stoppable +{ + /** + * Delegates this call to {@link org.junit.runner.notification.RunNotifier#pleaseStop()}. + */ + void pleaseStop(); +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit4Reflector481Test.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit4Reflector481Test.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit4Reflector481Test.java index 7d4b102..896af3e 100644 --- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit4Reflector481Test.java +++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit4Reflector481Test.java @@ -49,6 +49,37 @@ public class JUnit4Reflector481Test Description.createTestDescription( IgnoreWithDescription.class, "testSomething2", annotations ); Ignore annotatedIgnore = JUnit4Reflector.getAnnotatedIgnore( desc ); assertNotNull( annotatedIgnore ); + assertEquals( + "testSomething2" + "(org.apache.maven.surefire.junitcore.JUnit4Reflector481Test$IgnoreWithDescription)", + desc.getDisplayName() ); + assertEquals( "testSomething2" + + "(org.apache.maven.surefire.junitcore.JUnit4Reflector481Test$IgnoreWithDescription)", + desc.toString() ); + assertEquals( "org.apache.maven.surefire.junitcore.JUnit4Reflector481Test$IgnoreWithDescription", + desc.getClassName() ); + assertEquals( "testSomething2", desc.getMethodName() ); + assertEquals( 0, desc.getChildren().size() ); + assertEquals( 2, desc.getAnnotations().size() ); + assertSame( annotatedIgnore, desc.getAnnotation( Ignore.class ) ); + assertEquals( reason, annotatedIgnore.value() ); + } + + @Test + public void testGetAnnotatedIgnoreWithoutClass() + { + final Method testSomething2 = + ReflectionUtils.getMethod( IgnoreWithDescription.class, "testSomething2", EMPTY_CLASS_ARRAY ); + final Annotation[] annotations = testSomething2.getAnnotations(); + Description desc = Description.createSuiteDescription( "testSomething2", annotations ); + Ignore annotatedIgnore = JUnit4Reflector.getAnnotatedIgnore( desc ); + assertNotNull( annotatedIgnore ); + assertEquals( "testSomething2", desc.getDisplayName() ); + assertEquals( "testSomething2", desc.toString() ); + assertEquals( "testSomething2", desc.getClassName() ); + assertNull( desc.getMethodName() ); + assertEquals( 0, desc.getChildren().size() ); + assertEquals( 2, desc.getAnnotations().size() ); + assertSame( annotatedIgnore, desc.getAnnotation( Ignore.class ) ); assertEquals( reason, annotatedIgnore.value() ); } @@ -64,5 +95,26 @@ public class JUnit4Reflector481Test } } + @Test + public void testCreatePureDescription() + { + Description description = JUnit4Reflector.createDescription( "exception" ); + assertEquals( "exception", description.getDisplayName() ); + assertEquals( "exception", description.toString() ); + assertEquals( 0, description.getChildren().size() ); + } + @Test + public void testCreateDescription() + { + Ignore ignore = JUnit4Reflector.createIgnored( "error" ); + Description description = JUnit4Reflector.createDescription( "exception", ignore ); + assertEquals( "exception", description.getDisplayName() ); + assertEquals( "exception", description.toString() ); + assertEquals( "exception", description.getClassName() ); + assertEquals( 0, description.getChildren().size() ); + Ignore annotatedIgnore = JUnit4Reflector.getAnnotatedIgnore( description ); + assertNotNull( annotatedIgnore ); + assertEquals( "error", annotatedIgnore.value() ); + } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java index 538b31a..01aa81f 100644 --- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java +++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java @@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.plugin.surefire.report.DefaultReporterFactory; import org.apache.maven.surefire.booter.BaseProviderFactory; import org.apache.maven.surefire.booter.ProviderParameterNames; +import org.apache.maven.surefire.common.junit4.Notifier; import org.apache.maven.surefire.report.ConsoleLogger; import org.apache.maven.surefire.report.DefaultConsoleReporter; import org.apache.maven.surefire.report.ReporterConfiguration; @@ -111,7 +112,8 @@ public class Surefire746Test // JUnitCoreWrapper#execute() is calling JUnit4RunListener#rethrowAnyTestMechanismFailures() // and rethrows a failure which happened in listener exception.expect( TestSetFailedException.class ); - JUnitCoreWrapper.execute( new Logger(), testsToRun, jUnitCoreParameters, customRunListeners, null ); + new JUnitCoreWrapper( new Notifier(), jUnitCoreParameters, new Logger(), false ) + .execute( testsToRun, customRunListeners, null ); } finally { http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng-utils/pom.xml ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng-utils/pom.xml b/surefire-providers/surefire-testng-utils/pom.xml index 64d8518..8fc1513 100644 --- a/surefire-providers/surefire-testng-utils/pom.xml +++ b/surefire-providers/surefire-testng-utils/pom.xml @@ -49,7 +49,7 @@ <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> - <version>5.7</version> + <version>5.10</version> <classifier>jdk15</classifier> <scope>provided</scope> </dependency> http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastEventsSingleton.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastEventsSingleton.java b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastEventsSingleton.java new file mode 100644 index 0000000..523ce8f --- /dev/null +++ b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastEventsSingleton.java @@ -0,0 +1,53 @@ +package org.apache.maven.surefire.testng.utils; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Stores and retrieves atomic events + * used by {@link FailFastNotifier} and TestNG provider. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +public final class FailFastEventsSingleton +{ + private static final FailFastEventsSingleton INSTANCE = new FailFastEventsSingleton(); + + private volatile boolean skipAfterFailure; + + private FailFastEventsSingleton() + { + } + + public static FailFastEventsSingleton getInstance() + { + return INSTANCE; + } + + public boolean isSkipAfterFailure() + { + return skipAfterFailure; + } + + public void setSkipOnNextTest() + { + this.skipAfterFailure = true; + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastListener.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastListener.java b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastListener.java new file mode 100644 index 0000000..d3d5c00 --- /dev/null +++ b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastListener.java @@ -0,0 +1,77 @@ +package org.apache.maven.surefire.testng.utils; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; + +/** + * Sends an even in {@link FailFastEventsSingleton} that failure has appeared. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +public class FailFastListener + implements ITestListener +{ + private final Stoppable stoppable; + + public FailFastListener( Stoppable stoppable ) + { + this.stoppable = stoppable; + } + + public void onTestStart( ITestResult result ) + { + + } + + public void onTestSuccess( ITestResult result ) + { + + } + + public void onTestFailure( ITestResult result ) + { + FailFastEventsSingleton.getInstance().setSkipOnNextTest(); + stoppable.pleaseStop(); + } + + public void onTestSkipped( ITestResult result ) + { + + } + + public void onTestFailedButWithinSuccessPercentage( ITestResult result ) + { + + } + + public void onStart( ITestContext context ) + { + + } + + public void onFinish( ITestContext context ) + { + + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastNotifier.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastNotifier.java b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastNotifier.java new file mode 100644 index 0000000..735c2ce --- /dev/null +++ b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/FailFastNotifier.java @@ -0,0 +1,50 @@ +package org.apache.maven.surefire.testng.utils; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.testng.IInvokedMethod; +import org.testng.IInvokedMethodListener; +import org.testng.ITestResult; +import org.testng.SkipException; + +/** + * Notifies TestNG core skipping remaining tests after first failure has appeared. + * + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +public class FailFastNotifier + implements IInvokedMethodListener +{ + + public void beforeInvocation( IInvokedMethod iInvokedMethod, ITestResult iTestResult ) + { + if ( FailFastEventsSingleton.getInstance().isSkipAfterFailure() ) + { + throw new SkipException( "Skipped after failure. See parameter [skipAfterFailureCount] " + + "in surefire or failsafe plugin." ); + } + } + + public void afterInvocation( IInvokedMethod iInvokedMethod, ITestResult iTestResult ) + { + + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/Stoppable.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/Stoppable.java b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/Stoppable.java new file mode 100644 index 0000000..c7be682 --- /dev/null +++ b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/Stoppable.java @@ -0,0 +1,32 @@ +package org.apache.maven.surefire.testng.utils; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @author <a href="mailto:tibordig...@apache.org">Tibor Digana (tibor17)</a> + * @since 2.19 + */ +public interface Stoppable +{ + /** + * Delegates this call to {@link org.apache.maven.surefire.report.RunListener#testExecutionSkippedByUser()}. + */ + void pleaseStop(); +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/2a944f06/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java index 678280f..5297276 100644 --- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java +++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java @@ -79,9 +79,11 @@ public class TestNGDirectoryTestSuite private final List<CommandLineOption> mainCliOptions; + private final boolean isFailFast; + public TestNGDirectoryTestSuite( String testSourceDirectory, Map<String, String> confOptions, File reportsDirectory, TestListResolver methodFilter, RunOrderCalculator runOrderCalculator, - ScanResult scanResult, List<CommandLineOption> mainCliOptions ) + ScanResult scanResult, List<CommandLineOption> mainCliOptions, boolean isFailFast ) { this.runOrderCalculator = runOrderCalculator; this.options = confOptions; @@ -94,6 +96,7 @@ public class TestNGDirectoryTestSuite this.junitTestAnnotation = findJUnitTestAnnotation(); this.junitOptions = createJUnitOptions(); this.mainCliOptions = mainCliOptions; + this.isFailFast = isFailFast; } public void execute( TestsToRun testsToRun, ReporterFactory reporterManagerFactory ) @@ -128,7 +131,7 @@ public class TestNGDirectoryTestSuite final Map<String, String> optionsToUse = isJUnitTest( testClass ) ? junitOptions : options; TestNGExecutor.run( new Class<?>[]{ testClass }, testSourceDirectory, optionsToUse, reporter, this, - reportsDirectory, methodFilter, mainCliOptions ); + reportsDirectory, methodFilter, mainCliOptions, isFailFast ); finishTestSuite( reporter, this ); } @@ -218,14 +221,14 @@ public class TestNGDirectoryTestSuite Class<?>[] testClasses = testNgTestClasses.toArray( new Class<?>[testNgTestClasses.size()] ); TestNGExecutor.run( testClasses, testSourceDirectory, options, reporterManager, this, - testNgReportsDirectory, methodFilter, mainCliOptions ); + testNgReportsDirectory, methodFilter, mainCliOptions, isFailFast ); if ( !junitTestClasses.isEmpty() ) { testClasses = junitTestClasses.toArray( new Class[junitTestClasses.size()] ); TestNGExecutor.run( testClasses, testSourceDirectory, junitOptions, reporterManager, this, - junitReportsDirectory, methodFilter, mainCliOptions ); + junitReportsDirectory, methodFilter, mainCliOptions, isFailFast ); } finishTestSuite( reporterManager, this ); @@ -295,7 +298,7 @@ public class TestNGDirectoryTestSuite startTestSuite( reporter, this ); TestNGExecutor.run( new Class<?>[] { testSet.getTestClass() }, testSourceDirectory, options, reporter, - this, reportsDirectory, methodFilter, mainCliOptions ); + this, reportsDirectory, methodFilter, mainCliOptions, isFailFast ); finishTestSuite( reporter, this ); }