You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2015/09/06 22:58:46 UTC

[15/17] maven-surefire git commit: [SUREFIRE-580] configuration parameter 'skipAfterFailureCount'

[SUREFIRE-580] configuration parameter 'skipAfterFailureCount'


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/779e3811
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/779e3811
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/779e3811

Branch: refs/heads/master
Commit: 779e381102a8f882e58c95ad3e50eadca170cba7
Parents: 1b7fe2d
Author: Tibor17 <ti...@lycos.com>
Authored: Sat Sep 5 01:15:07 2015 +0200
Committer: Tibor17 <ti...@lycos.com>
Committed: Sun Sep 6 22:58:04 2015 +0200

----------------------------------------------------------------------
 .../surefire/booterclient/ForkStarter.java      |  12 ++-
 surefire-api/pom.xml                            |   6 ++
 .../util/internal/ConcurrencyUtils.java         |  64 ++++++++++++
 .../java/org/apache/maven/JUnit4SuiteTest.java  |  78 ++++++++++++++
 .../util/internal/ConcurrencyUtilsTest.java     | 104 +++++++++++++++++++
 .../maven/surefire/common/junit4/Notifier.java  |  35 ++++---
 .../maven/surefire/common/junit4/Stoppable.java |  35 +++++++
 .../surefire/junit4/JUnit4FailFastListener.java |  13 +--
 .../maven/surefire/junit4/JUnit4Provider.java   |  11 +-
 .../junitcore/JUnit47FailFastListener.java      |   5 +-
 .../maven/surefire/junitcore/JUnitCore.java     |  11 --
 .../surefire/junitcore/JUnitCoreProvider.java   |   9 +-
 .../surefire/junitcore/JUnitCoreWrapper.java    |  15 ++-
 .../maven/surefire/junitcore/Stoppable.java     |  32 ------
 .../surefire/testng/utils/FailFastListener.java |   3 +-
 .../maven/surefire/testng/utils/Stoppable.java  |   4 +-
 .../testng/TestNGDirectoryTestSuite.java        |  15 +--
 .../maven/surefire/testng/TestNGExecutor.java   |  43 +++++---
 .../maven/surefire/testng/TestNGProvider.java   |  10 +-
 .../surefire/testng/TestNGXmlTestSuite.java     |   8 +-
 20 files changed, 397 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index 632834f..396e99f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -67,7 +67,7 @@ import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import static org.apache.maven.shared.utils.cli.CommandLineUtils.executeCommandLine;
@@ -79,6 +79,7 @@ import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDae
 import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.createCopyAndReplaceForkNumPlaceholder;
 import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.
     TestLessInputStream.TestLessInputStreamBuilder;
+import static org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
 import static org.apache.maven.surefire.booter.Classpath.join;
 import static org.apache.maven.surefire.booter.SystemPropertyManager.writePropertiesFile;
 import static org.apache.maven.surefire.suite.RunResult.timeout;
@@ -248,7 +249,7 @@ public class ForkStarter
                 testStreams.add( new TestProvidingInputStream( tests ) );
             }
 
-            final AtomicBoolean notifyStreamsToSkipTestsJustNow = new AtomicBoolean();
+            final AtomicInteger notifyStreamsToSkipTestsJustNow = new AtomicInteger();
             Collection<Future<RunResult>> results = new ArrayList<Future<RunResult>>( forkCount );
             for ( final TestProvidingInputStream testProvidingInputStream : testStreams )
             {
@@ -267,7 +268,7 @@ public class ForkStarter
                             @Override
                             protected void stopOnNextTest()
                             {
-                                if ( notifyStreamsToSkipTestsJustNow.compareAndSet( false, true ) )
+                                if ( countDownToZero( notifyStreamsToSkipTestsJustNow ) )
                                 {
                                     notifyStreamsToSkipTests( testStreams );
                                 }
@@ -306,7 +307,8 @@ public class ForkStarter
         executorService.setThreadFactory( threadFactory );
         try
         {
-            final AtomicBoolean notifyStreamsToSkipTestsJustNow = new AtomicBoolean();
+            int failFastCount = providerConfiguration.getSkipAfterFailureCount();
+            final AtomicInteger notifyStreamsToSkipTestsJustNow = new AtomicInteger( failFastCount );
             final TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
             for ( final Object testSet : getSuitesIterator() )
             {
@@ -324,7 +326,7 @@ public class ForkStarter
                             @Override
                             protected void stopOnNextTest()
                             {
-                                if ( notifyStreamsToSkipTestsJustNow.compareAndSet( false, true ) )
+                                if ( countDownToZero( notifyStreamsToSkipTestsJustNow ) )
                                 {
                                     builder.getCachableCommands().skipSinceNextTest();
                                 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-api/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index 6f66e66..3567b93 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -42,6 +42,12 @@
     <plugins>
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <redirectTestOutputToFile>true</redirectTestOutputToFile>
+          <includes>
+            <include>**/JUnit4SuiteTest.java</include>
+          </includes>
+        </configuration>
         <dependencies>
           <dependency>
             <groupId>org.apache.maven.surefire</groupId>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ConcurrencyUtils.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ConcurrencyUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ConcurrencyUtils.java
new file mode 100644
index 0000000..6cfc6bf
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ConcurrencyUtils.java
@@ -0,0 +1,64 @@
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * 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 java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Concurrency utilities.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.19
+ */
+public final class ConcurrencyUtils
+{
+    private ConcurrencyUtils()
+    {
+        throw new IllegalStateException( "not instantiable constructor" );
+    }
+
+    /**
+     * Decreases {@code counter} to zero, or does not change the counter if negative.
+     * This method pretends been atomic. Only one thread can succeed setting the counter to zero.
+     *
+     * @param counter atomic counter
+     * @return {@code true} if this Thread modified concurrent counter from any positive number down to zero.
+     */
+    @SuppressWarnings( "checkstyle:emptyforiteratorpad" )
+    public static boolean countDownToZero( AtomicInteger counter )
+    {
+        for (;;)
+        {
+            int c = counter.get();
+            if ( c > 0 )
+            {
+                int newCounter = c - 1;
+                if ( counter.compareAndSet( c, newCounter ) )
+                {
+                    return newCounter == 0;
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
new file mode 100644
index 0000000..c2ec153
--- /dev/null
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -0,0 +1,78 @@
+package org.apache.maven;
+
+/*
+ * 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 junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import org.apache.maven.plugin.surefire.runorder.ThreadedExecutionSchedulerTest;
+import org.apache.maven.surefire.SpecificTestClassFilterTest;
+import org.apache.maven.surefire.booter.ForkingRunListenerTest;
+import org.apache.maven.surefire.booter.MasterProcessCommandTest;
+import org.apache.maven.surefire.booter.SurefireReflectorTest;
+import org.apache.maven.surefire.report.LegacyPojoStackTraceWriterTest;
+import org.apache.maven.surefire.suite.RunResultTest;
+import org.apache.maven.surefire.testset.ResolvedTestTest;
+import org.apache.maven.surefire.testset.TestListResolverTest;
+import org.apache.maven.surefire.util.DefaultDirectoryScannerTest;
+import org.apache.maven.surefire.util.RunOrderCalculatorTest;
+import org.apache.maven.surefire.util.RunOrderTest;
+import org.apache.maven.surefire.util.ScanResultTest;
+import org.apache.maven.surefire.util.TestsToRunTest;
+import org.apache.maven.surefire.util.UrlUtilsTest;
+import org.apache.maven.surefire.util.internal.ByteBufferTest;
+import org.apache.maven.surefire.util.internal.ConcurrencyUtilsTest;
+import org.apache.maven.surefire.util.internal.StringUtilsTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
+ *
+ * @author Tibor Digana (tibor17)
+ * @since 2.19
+ */
+@Suite.SuiteClasses( {
+    ThreadedExecutionSchedulerTest.class,
+    ForkingRunListenerTest.class,
+    MasterProcessCommandTest.class,
+    SurefireReflectorTest.class,
+    LegacyPojoStackTraceWriterTest.class,
+    RunResultTest.class,
+    ResolvedTestTest.class,
+    TestListResolverTest.class,
+    ByteBufferTest.class,
+    ConcurrencyUtilsTest.class,
+    StringUtilsTest.class,
+    DefaultDirectoryScannerTest.class,
+    RunOrderCalculatorTest.class,
+    RunOrderTest.class,
+    ScanResultTest.class,
+    TestsToRunTest.class,
+    UrlUtilsTest.class,
+    SpecificTestClassFilterTest.class
+} )
+@RunWith( Suite.class )
+public class JUnit4SuiteTest
+{
+    public static Test suite()
+    {
+        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ConcurrencyUtilsTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ConcurrencyUtilsTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ConcurrencyUtilsTest.java
new file mode 100644
index 0000000..516f885
--- /dev/null
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ConcurrencyUtilsTest.java
@@ -0,0 +1,104 @@
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * 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.Test;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Concurrency utilities.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.19
+ */
+public class ConcurrencyUtilsTest
+{
+
+    @Test
+    public void countDownShouldBeUnchangedAsZero$NegativeTest()
+    {
+        AtomicInteger atomicCounter = new AtomicInteger( 0 );
+        assertFalse( countDownToZero( atomicCounter ) );
+        assertThat( atomicCounter.get(), is( 0 ) );
+    }
+
+    @Test
+    public void countDownShouldBeUnchangedAsNegative$NegativeTest()
+    {
+        AtomicInteger atomicCounter = new AtomicInteger( -1 );
+        assertFalse( countDownToZero( atomicCounter ) );
+        assertThat( atomicCounter.get(), is( -1 ) );
+    }
+
+    @Test
+    public void countDownShouldBeDecreasedByOneThreadModification()
+    {
+        AtomicInteger atomicCounter = new AtomicInteger( 10 );
+        assertFalse( countDownToZero( atomicCounter ) );
+        assertThat( atomicCounter.get(), is( 9 ) );
+    }
+
+    @Test
+    public void countDownToZeroShouldBeDecreasedByOneThreadModification()
+    {
+        AtomicInteger atomicCounter = new AtomicInteger( 1 );
+        assertTrue( countDownToZero( atomicCounter ) );
+        assertThat( atomicCounter.get(), is( 0 ) );
+    }
+
+    @Test
+    public void countDownShouldBeDecreasedByTwoThreadsModification()
+        throws ExecutionException, InterruptedException
+    {
+        final AtomicInteger atomicCounter = new AtomicInteger( 3 );
+
+        FutureTask<Boolean> task = new FutureTask<Boolean>( new Callable<Boolean>()
+        {
+            public Boolean call()
+                throws Exception
+            {
+                return countDownToZero( atomicCounter );
+            }
+        } );
+        Thread t = new Thread( task );
+        t.start();
+
+        assertFalse( countDownToZero( atomicCounter ) );
+
+        assertFalse( task.get() );
+
+        assertThat( atomicCounter.get(), is( 1 ) );
+
+        assertTrue( countDownToZero( atomicCounter ) );
+
+        assertThat( atomicCounter.get(), is( 0 ) );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
index e9136e1..5748e4b 100644
--- 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
@@ -25,6 +25,9 @@ import org.junit.runner.notification.RunNotifier;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
 
 /**
  * Extends {@link RunNotifier JUnit notifier},
@@ -35,31 +38,29 @@ import java.util.Iterator;
  * @since 2.19
  */
 public class Notifier
-    extends RunNotifier
+    extends RunNotifier implements Stoppable
 {
     private final Collection<RunListener> listeners = new ArrayList<RunListener>();
 
-    private JUnit4RunListener reporter;
+    private final AtomicInteger skipAfterFailureCount;
 
-    @Override
-    public void pleaseStop()
+    private final JUnit4RunListener reporter;
+
+    public Notifier( JUnit4RunListener reporter, int skipAfterFailureCount )
     {
-        super.pleaseStop();
-        reporter.testExecutionSkippedByUser();
+        addListener( reporter );
+        this.reporter = reporter;
+        this.skipAfterFailureCount = new AtomicInteger( skipAfterFailureCount );
     }
 
-    /**
-     * 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 )
+    public void fireStopEvent()
     {
-        JUnit4RunListener old = this.reporter;
-        this.reporter = reporter;
-        addListener( reporter );
-        return old;
+        if ( countDownToZero( skipAfterFailureCount ) )
+        {
+            pleaseStop();
+        }
+
+        reporter.testExecutionSkippedByUser();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Stoppable.java
----------------------------------------------------------------------
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Stoppable.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Stoppable.java
new file mode 100644
index 0000000..376d631
--- /dev/null
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Stoppable.java
@@ -0,0 +1,35 @@
+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.
+ */
+
+/**
+ * Covers configuration parameter <em>skipAfterFailureCount</em>.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.19
+ * @see org.apache.maven.surefire.common.junit4.Notifier
+ */
+public interface Stoppable
+{
+    /**
+     * Fire stop even to plugin process and/or call {@link org.junit.runner.notification.RunNotifier#pleaseStop()}.
+     */
+    void fireStopEvent();
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
index d45b678..84346e7 100644
--- 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
@@ -19,12 +19,13 @@ package org.apache.maven.surefire.junit4;
  * under the License.
  */
 
+import org.apache.maven.surefire.common.junit4.Notifier;
+import org.apache.maven.surefire.common.junit4.Stoppable;
 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.
+ * Calling {@link Notifier#fireStopEvent()} if failure happens.
  *
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
  * @since 2.19
@@ -32,17 +33,17 @@ import org.junit.runner.notification.RunNotifier;
 final class JUnit4FailFastListener
     extends RunListener
 {
-    private final RunNotifier notifier;
+    private final Stoppable stoppable;
 
-    JUnit4FailFastListener( RunNotifier notifier )
+    JUnit4FailFastListener( Notifier stoppable )
     {
-        this.notifier = notifier;
+        this.stoppable = stoppable;
     }
 
     @Override
     public void testFailure( Failure failure )
         throws Exception
     {
-        notifier.pleaseStop();
+        stoppable.fireStopEvent();
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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 e8f041d..2276eac 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
@@ -146,8 +146,7 @@ public class JUnit4Provider
 
         startCapture( (ConsoleOutputReceiver) reporter );
 
-        Notifier notifier = new Notifier();
-        notifier.setReporter( new JUnit4RunListener( reporter ) );
+        Notifier notifier = new Notifier( new JUnit4RunListener( reporter ), getSkipAfterFailureCount() );
         if ( isFailFast() )
         {
             notifier.addListener( new JUnit4FailFastListener( notifier ) );
@@ -193,6 +192,11 @@ public class JUnit4Provider
         return providerParameters.getSkipAfterFailureCount() > 0;
     }
 
+    private int getSkipAfterFailureCount()
+    {
+        return isFailFast() && !isRerunFailingTests() ? providerParameters.getSkipAfterFailureCount() : 0;
+    }
+
     private void closeCommandsReader()
     {
         if ( commandsReader != null )
@@ -227,7 +231,8 @@ public class JUnit4Provider
             if ( isFailFast() && e instanceof StoppedByUserException )
             {
                 String reason = e.getClass().getName();
-                notifier.fireTestIgnored( createDescription( clazz.getName(), createIgnored( reason ) ) );
+                Description skippedTest = createDescription( clazz.getName(), createIgnored( reason ) );
+                notifier.fireTestIgnored( skippedTest );
             }
             else
             {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
index dda6b68..0f6efc9 100644
--- 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
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.junitcore;
  * under the License.
  */
 
+import org.apache.maven.surefire.common.junit4.Stoppable;
 import org.junit.runner.Description;
 import org.junit.runner.notification.Failure;
 import org.junit.runner.notification.RunListener;
@@ -27,7 +28,7 @@ import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
- * Calling {@link Stoppable#pleaseStop()} if failure appeared.
+ * Calling {@link Stoppable#fireStopEvent()} if failure happens.
  *
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
  * @since 2.19
@@ -60,6 +61,6 @@ final class JUnit47FailFastListener
     public void testFailure( Failure failure )
         throws Exception
     {
-        stoppable.pleaseStop();
+        stoppable.fireStopEvent();
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
index 7f1a03a..9935d9a 100644
--- 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
@@ -29,15 +29,12 @@ 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:tibordigana@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;
 
@@ -79,12 +76,4 @@ class JUnitCore
     protected void afterFinished()
     {
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void pleaseStop()
-    {
-        notifier.pleaseStop();
-    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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 243cca0..29687ef 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
@@ -145,8 +145,8 @@ public class JUnitCoreProvider
             }
         }
 
-        Notifier notifier = new Notifier();
-        notifier.setReporter( createRunListener( reporterFactory, consoleLogger ) );
+        Notifier notifier =
+            new Notifier( createRunListener( reporterFactory, consoleLogger ), getSkipAfterFailureCount() );
 
         // Add test failure listener
         JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
@@ -195,6 +195,11 @@ public class JUnitCoreProvider
         return providerParameters.getSkipAfterFailureCount() > 0;
     }
 
+    private int getSkipAfterFailureCount()
+    {
+        return isFailFast() && !isRerunFailingTests() ? providerParameters.getSkipAfterFailureCount() : 0;
+    }
+
     private void closeCommandsReader()
     {
         if ( commandsReader != null )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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 e0c9f9e..eb41217 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
@@ -27,6 +27,7 @@ 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.Description;
 import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.manipulation.Filter;
@@ -36,7 +37,6 @@ import org.junit.runner.notification.StoppedByUserException;
 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;
@@ -54,8 +54,6 @@ final class JUnitCoreWrapper
     private final ConsoleLogger logger;
     private final boolean failFast;
 
-    private Object o = new Random().nextInt();
-
     JUnitCoreWrapper( Notifier notifier, JUnitCoreParameters jUnitCoreParameters, ConsoleLogger logger,
                       boolean failFast )
     {
@@ -86,7 +84,7 @@ final class JUnitCoreWrapper
 
     private JUnitCore createJUnitCore( final Notifier notifier, Collection<RunListener> listeners )
     {
-        JUnitCore junitCore = new JUnitCore( notifier );
+        JUnitCore junitCore = new JUnitCore();
 
         // custom listeners added last
         notifier.addListeners( listeners );
@@ -154,10 +152,10 @@ final class JUnitCoreWrapper
     {
         private final JUnit47FailFastListener failFastListener;
 
-        JUnitCore( Notifier notifier )
+        JUnitCore()
         {
             super( notifier );
-            failFastListener = failFast ? new JUnit47FailFastListener( this ) : null;
+            failFastListener = failFast ? new JUnit47FailFastListener( notifier ) : null;
             if ( failFastListener != null )
             {
                 notifier.addListener( failFastListener );
@@ -188,10 +186,11 @@ final class JUnitCoreWrapper
                 if ( stoppedTests != null )
                 {
                     String reason = e.getClass().getName();
-                    Ignore reasonForIgnoredTest = createIgnored( reason );
+                    Ignore reasonForSkippedTest = createIgnored( reason );
                     for ( String clazz; ( clazz = stoppedTests.poll() ) != null; )
                     {
-                        notifier.fireTestIgnored( createDescription( clazz, reasonForIgnoredTest ) );
+                        Description skippedTest = createDescription( clazz, reasonForSkippedTest );
+                        notifier.fireTestIgnored( skippedTest );
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
deleted file mode 100644
index 2450e64..0000000
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/Stoppable.java
+++ /dev/null
@@ -1,32 +0,0 @@
-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:tibordigana@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/779e3811/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
index d3d5c00..91f3461 100644
--- 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
@@ -51,8 +51,7 @@ public class FailFastListener
 
     public void onTestFailure( ITestResult result )
     {
-        FailFastEventsSingleton.getInstance().setSkipOnNextTest();
-        stoppable.pleaseStop();
+        stoppable.fireStopEvent();
     }
 
     public void onTestSkipped( ITestResult result )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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
index c7be682..dd172d2 100644
--- 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
@@ -20,6 +20,8 @@ package org.apache.maven.surefire.testng.utils;
  */
 
 /**
+ * Covers configuration parameter <em>skipAfterFailureCount</em>.
+ *
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
  * @since 2.19
  */
@@ -28,5 +30,5 @@ public interface Stoppable
     /**
      * Delegates this call to {@link org.apache.maven.surefire.report.RunListener#testExecutionSkippedByUser()}.
      */
-    void pleaseStop();
+    void fireStopEvent();
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/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 5297276..a721bbc 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,11 +79,12 @@ public class TestNGDirectoryTestSuite
 
     private final List<CommandLineOption> mainCliOptions;
 
-    private final boolean isFailFast;
+    private final int skipAfterFailureCount;
 
     public TestNGDirectoryTestSuite( String testSourceDirectory, Map<String, String> confOptions, File reportsDirectory,
                                      TestListResolver methodFilter, RunOrderCalculator runOrderCalculator,
-                                     ScanResult scanResult, List<CommandLineOption> mainCliOptions, boolean isFailFast )
+                                     ScanResult scanResult, List<CommandLineOption> mainCliOptions,
+                                     int skipAfterFailureCount )
     {
         this.runOrderCalculator = runOrderCalculator;
         this.options = confOptions;
@@ -96,7 +97,7 @@ public class TestNGDirectoryTestSuite
         this.junitTestAnnotation = findJUnitTestAnnotation();
         this.junitOptions = createJUnitOptions();
         this.mainCliOptions = mainCliOptions;
-        this.isFailFast = isFailFast;
+        this.skipAfterFailureCount = skipAfterFailureCount;
     }
 
     public void execute( TestsToRun testsToRun, ReporterFactory reporterManagerFactory )
@@ -131,7 +132,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, isFailFast );
+                            reportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
 
         finishTestSuite( reporter, this );
     }
@@ -221,14 +222,14 @@ public class TestNGDirectoryTestSuite
         Class<?>[] testClasses = testNgTestClasses.toArray( new Class<?>[testNgTestClasses.size()] );
 
         TestNGExecutor.run( testClasses, testSourceDirectory, options, reporterManager, this,
-                            testNgReportsDirectory, methodFilter, mainCliOptions, isFailFast );
+                            testNgReportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
 
         if ( !junitTestClasses.isEmpty() )
         {
             testClasses = junitTestClasses.toArray( new Class[junitTestClasses.size()] );
 
             TestNGExecutor.run( testClasses, testSourceDirectory, junitOptions, reporterManager, this,
-                                junitReportsDirectory, methodFilter, mainCliOptions, isFailFast );
+                                junitReportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
         }
 
         finishTestSuite( reporterManager, this );
@@ -298,7 +299,7 @@ public class TestNGDirectoryTestSuite
         startTestSuite( reporter, this );
 
         TestNGExecutor.run( new Class<?>[] { testSet.getTestClass() }, testSourceDirectory, options, reporter,
-                            this, reportsDirectory, methodFilter, mainCliOptions, isFailFast );
+                            this, reportsDirectory, methodFilter, mainCliOptions, skipAfterFailureCount );
 
         finishTestSuite( reporter, this );
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGExecutor.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGExecutor.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGExecutor.java
index d481bb2..5a91db0 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGExecutor.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGExecutor.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.booter.ProviderParameterNames;
 import org.apache.maven.surefire.cli.CommandLineOption;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.testng.conf.Configurator;
+import org.apache.maven.surefire.testng.utils.FailFastEventsSingleton;
 import org.apache.maven.surefire.testng.utils.FailFastListener;
 import org.apache.maven.surefire.testng.utils.Stoppable;
 import org.apache.maven.surefire.testset.TestListResolver;
@@ -45,8 +46,10 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.apache.maven.surefire.util.ReflectionUtils.instantiate;
+import static org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
 
 /**
  * Contains utility methods for executing TestNG.
@@ -73,7 +76,8 @@ public class TestNGExecutor
     public static void run( Class<?>[] testClasses, String testSourceDirectory,
                             Map<String, String> options, // string,string because TestNGMapConfigurator#configure()
                             RunListener reportManager, TestNgTestSuite suite, File reportsDirectory,
-                            TestListResolver methodFilter, List<CommandLineOption> mainCliOptions, boolean isFailFast )
+                            TestListResolver methodFilter, List<CommandLineOption> mainCliOptions,
+                            int skipAfterFailureCount )
         throws TestSetFailedException
     {
         TestNG testng = new TestNG( true );
@@ -123,7 +127,7 @@ public class TestNGExecutor
 
         testng.setXmlSuites( xmlSuites );
         configurator.configure( testng, options );
-        postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory, isFailFast );
+        postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory, skipAfterFailureCount );
         testng.run();
     }
 
@@ -265,13 +269,13 @@ public class TestNGExecutor
     public static void run( List<String> suiteFiles, String testSourceDirectory,
                             Map<String, String> options, // string,string because TestNGMapConfigurator#configure()
                             RunListener reportManager, TestNgTestSuite suite, File reportsDirectory,
-                            boolean isFailFast )
+                            int skipAfterFailureCount )
         throws TestSetFailedException
     {
         TestNG testng = new TestNG( true );
         Configurator configurator = getConfigurator( options.get( "testng.configurator" ) );
         configurator.configure( testng, options );
-        postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory, isFailFast );
+        postConfigure( testng, testSourceDirectory, reportManager, suite, reportsDirectory, skipAfterFailureCount );
         testng.setTestSuites( suiteFiles );
         testng.run();
     }
@@ -297,7 +301,7 @@ public class TestNGExecutor
     }
 
     private static void postConfigure( TestNG testNG, String sourcePath, final RunListener reportManager,
-                                       TestNgTestSuite suite, File reportsDirectory, boolean skipAfterFailure )
+                                       TestNgTestSuite suite, File reportsDirectory, int skipAfterFailureCount )
         throws TestSetFailedException
     {
         // turn off all TestNG output
@@ -306,19 +310,12 @@ public class TestNGExecutor
         TestNGReporter reporter = createTestNGReporter( reportManager, suite );
         testNG.addListener( (Object) reporter );
 
-        if ( skipAfterFailure )
+        if ( skipAfterFailureCount > 0 )
         {
             ClassLoader cl = Thread.currentThread().getContextClassLoader();
             testNG.addListener( instantiate( cl, "org.apache.maven.surefire.testng.utils.FailFastNotifier",
                                              Object.class ) );
-            Stoppable stoppable = new Stoppable()
-            {
-                public void pleaseStop()
-                {
-                    reportManager.testExecutionSkippedByUser();
-                }
-            };
-            testNG.addListener( new FailFastListener( stoppable ) );
+            testNG.addListener( new FailFastListener( createStoppable( reportManager, skipAfterFailureCount ) ) );
         }
 
         // FIXME: use classifier to decide if we need to pass along the source dir (only for JDK14)
@@ -330,6 +327,24 @@ public class TestNGExecutor
         testNG.setOutputDirectory( reportsDirectory.getAbsolutePath() );
     }
 
+    private static Stoppable createStoppable( final RunListener reportManager, int skipAfterFailureCount )
+    {
+        final AtomicInteger currentFaultCount = new AtomicInteger( skipAfterFailureCount );
+
+        return new Stoppable()
+        {
+            public void fireStopEvent()
+            {
+                if ( countDownToZero( currentFaultCount ) )
+                {
+                    FailFastEventsSingleton.getInstance().setSkipOnNextTest();
+                }
+
+                reportManager.testExecutionSkippedByUser();
+            }
+        };
+    }
+
     // If we have access to IResultListener, return a ConfigurationAwareTestNGReporter
     // But don't cause NoClassDefFoundErrors if it isn't available; just return a regular TestNGReporter instead
     private static TestNGReporter createTestNGReporter( RunListener reportManager, TestNgTestSuite suite )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
index 8777ceb..77b5c75 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
@@ -149,6 +149,11 @@ public class TestNGProvider
         return providerParameters.getSkipAfterFailureCount() > 0;
     }
 
+    private int getSkipAfterFailureCount()
+    {
+        return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;
+    }
+
     private void closeCommandsReader()
     {
         if ( commandsReader != null )
@@ -174,7 +179,8 @@ public class TestNGProvider
     {
         return new TestNGDirectoryTestSuite( testRequest.getTestSourceDirectory().toString(), providerProperties,
                                              reporterConfiguration.getReportsDirectory(), createMethodFilter(),
-                                             runOrderCalculator, scanResult, mainCliOptions, isFailFast() );
+                                             runOrderCalculator, scanResult, mainCliOptions,
+                                             getSkipAfterFailureCount() );
     }
 
     private TestNGXmlTestSuite newXmlSuite()
@@ -182,7 +188,7 @@ public class TestNGProvider
         return new TestNGXmlTestSuite( testRequest.getSuiteXmlFiles(),
                                        testRequest.getTestSourceDirectory().toString(),
                                        providerProperties,
-                                       reporterConfiguration.getReportsDirectory(), isFailFast() );
+                                       reporterConfiguration.getReportsDirectory(), getSkipAfterFailureCount() );
     }
 
     @SuppressWarnings( "unchecked" )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/779e3811/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGXmlTestSuite.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGXmlTestSuite.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGXmlTestSuite.java
index bf105fe..ab9ae7f 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGXmlTestSuite.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGXmlTestSuite.java
@@ -49,7 +49,7 @@ public class TestNGXmlTestSuite
 
     private final File reportsDirectory;
 
-    private final boolean isFailFast;
+    private final int skipAfterFailureCount;
 
     // Not really used
     private Map<File, String> testSets;
@@ -59,13 +59,13 @@ public class TestNGXmlTestSuite
      * xml file(s). The XML files are suite definitions files according to TestNG DTD.
      */
     public TestNGXmlTestSuite( List<File> suiteFiles, String testSourceDirectory, Map<String, String> confOptions,
-                               File reportsDirectory, boolean isFailFast )
+                               File reportsDirectory, int skipAfterFailureCount )
     {
         this.suiteFiles = suiteFiles;
         this.options = confOptions;
         this.testSourceDirectory = testSourceDirectory;
         this.reportsDirectory = reportsDirectory;
-        this.isFailFast = isFailFast;
+        this.skipAfterFailureCount = skipAfterFailureCount;
     }
 
     public void execute( ReporterFactory reporterManagerFactory )
@@ -81,7 +81,7 @@ public class TestNGXmlTestSuite
 
         TestNGDirectoryTestSuite.startTestSuite( reporter, this );
         TestNGExecutor.run( suiteFilePaths, testSourceDirectory, options, reporter, this, reportsDirectory,
-                            isFailFast );
+                            skipAfterFailureCount );
         TestNGDirectoryTestSuite.finishTestSuite( reporter, this );
     }