You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ag...@apache.org on 2013/08/16 10:55:19 UTC

[1/3] reformat code + IT + junit.apt.vm + fork-options-and-parllel-execution.apt.vm

Updated Branches:
  refs/heads/master 911d374c7 -> a9d511a03


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ParallelComputerFactoryTest.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ParallelComputerFactoryTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ParallelComputerFactoryTest.java
index 90d773e..c3682ae 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ParallelComputerFactoryTest.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/ParallelComputerFactoryTest.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.junitcore;
  * under the License.
  */
 
+import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -28,9 +29,12 @@ import org.junit.experimental.theories.DataPoint;
 import org.junit.experimental.theories.Theories;
 import org.junit.experimental.theories.Theory;
 import org.junit.rules.ExpectedException;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
 import org.junit.runner.RunWith;
 
 import java.util.Properties;
+import java.util.concurrent.ExecutionException;
 
 import static org.apache.maven.surefire.junitcore.ParallelComputerFactory.*;
 import static org.apache.maven.surefire.junitcore.JUnitCoreParameters.*;
@@ -42,22 +46,24 @@ import static org.junit.Assert.*;
  * allocated thread resources in ParallelComputer by given {@link JUnitCoreParameters}.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see org.apache.maven.surefire.junitcore.ParallelComputerFactory
+ * @since 2.16
  */
-@RunWith(Theories.class)
+@RunWith( Theories.class )
 public final class ParallelComputerFactoryTest
 {
-    @Rule
-    public final ExpectedException exception = ExpectedException.none();
-
     @DataPoint
     public static final int CPU_1 = 1;
 
     @DataPoint
     public static final int CPU_4 = 4;
 
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    @Rule
+    public final Stopwatch runtime = new Stopwatch();
+
     @BeforeClass
     public static void beforeClass()
     {
@@ -70,16 +76,25 @@ public final class ParallelComputerFactoryTest
         ParallelComputerFactory.setDefaultAvailableProcessors();
     }
 
+    private static Properties parallel( String parallel )
+    {
+        Properties properties = new Properties();
+        properties.setProperty( PARALLEL_KEY, parallel );
+        return properties;
+    }
+
     @Test
-    public void unknownParallel() throws TestSetFailedException
+    public void unknownParallel()
+        throws TestSetFailedException
     {
         Properties properties = new Properties();
-        exception.expect( TestSetFailedException.class  );
+        exception.expect( TestSetFailedException.class );
         resolveConcurrency( new JUnitCoreParameters( properties ) );
     }
 
     @Test
-    public void unknownThreadCountSuites() throws TestSetFailedException
+    public void unknownThreadCountSuites()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "suites" ) );
         assertTrue( params.isParallelSuites() );
@@ -90,7 +105,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountClasses() throws TestSetFailedException
+    public void unknownThreadCountClasses()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "classes" ) );
         assertFalse( params.isParallelSuites() );
@@ -101,7 +117,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountMethods() throws TestSetFailedException
+    public void unknownThreadCountMethods()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "methods" ) );
         assertFalse( params.isParallelSuites() );
@@ -112,7 +129,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountBoth() throws TestSetFailedException
+    public void unknownThreadCountBoth()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "both" ) );
         assertFalse( params.isParallelSuites() );
@@ -123,7 +141,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountAll() throws TestSetFailedException
+    public void unknownThreadCountAll()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "all" ) );
         assertTrue( params.isParallelSuites() );
@@ -134,7 +153,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountSuitesAndClasses() throws TestSetFailedException
+    public void unknownThreadCountSuitesAndClasses()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "suitesAndClasses" ) );
         assertTrue( params.isParallelSuites() );
@@ -145,7 +165,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountSuitesAndMethods() throws TestSetFailedException
+    public void unknownThreadCountSuitesAndMethods()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "suitesAndMethods" ) );
         assertTrue( params.isParallelSuites() );
@@ -156,7 +177,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Test
-    public void unknownThreadCountClassesAndMethods() throws TestSetFailedException
+    public void unknownThreadCountClassesAndMethods()
+        throws TestSetFailedException
     {
         JUnitCoreParameters params = new JUnitCoreParameters( parallel( "classesAndMethods" ) );
         assertFalse( params.isParallelSuites() );
@@ -167,7 +189,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void useUnlimitedThreadsSuites( int cpu ) throws TestSetFailedException
+    public void useUnlimitedThreadsSuites( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -196,7 +219,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void useUnlimitedThreadsClasses( int cpu ) throws TestSetFailedException
+    public void useUnlimitedThreadsClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -225,7 +249,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void unlimitedThreadsMethods( int cpu ) throws TestSetFailedException
+    public void unlimitedThreadsMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -254,7 +279,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void unlimitedThreadsSuitesAndClasses( int cpu ) throws TestSetFailedException
+    public void unlimitedThreadsSuitesAndClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -284,7 +310,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void unlimitedThreadsSuitesAndMethods( int cpu ) throws TestSetFailedException
+    public void unlimitedThreadsSuitesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -314,7 +341,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void unlimitedThreadsClassesAndMethods( int cpu ) throws TestSetFailedException
+    public void unlimitedThreadsClassesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -344,7 +372,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void unlimitedThreadsAll( int cpu ) throws TestSetFailedException
+    public void unlimitedThreadsAll( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -375,7 +404,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountSuites( int cpu ) throws TestSetFailedException
+    public void threadCountSuites( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -393,7 +423,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountClasses( int cpu ) throws TestSetFailedException
+    public void threadCountClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -411,7 +442,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountMethods( int cpu ) throws TestSetFailedException
+    public void threadCountMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -429,7 +461,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountBoth( int cpu ) throws TestSetFailedException
+    public void threadCountBoth( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -447,7 +480,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountClassesAndMethods( int cpu ) throws TestSetFailedException
+    public void threadCountClassesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -465,7 +499,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountSuitesAndMethods( int cpu ) throws TestSetFailedException
+    public void threadCountSuitesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -483,7 +518,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountSuitesAndClasses( int cpu ) throws TestSetFailedException
+    public void threadCountSuitesAndClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -501,7 +537,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void threadCountAll( int cpu ) throws TestSetFailedException
+    public void threadCountAll( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -519,7 +556,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void everyThreadCountSuitesAndClasses( int cpu ) throws TestSetFailedException
+    public void everyThreadCountSuitesAndClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -533,7 +571,7 @@ public final class ParallelComputerFactoryTest
         assertTrue( params.isParallelSuites() );
         assertTrue( params.isParallelClasses() );
         assertFalse( params.isParallelMethod() );
-        assertThat( concurrency.capacity, is(3 * cpu) );
+        assertThat( concurrency.capacity, is( 3 * cpu ) );
         int concurrentSuites = (int) ( 0.34d * concurrency.capacity );
         assertThat( concurrency.suites, is( concurrentSuites ) );
         assertThat( concurrency.classes, is( concurrency.capacity - concurrentSuites ) );
@@ -541,7 +579,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void everyThreadCountSuitesAndMethods( int cpu ) throws TestSetFailedException
+    public void everyThreadCountSuitesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -563,7 +602,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void everyThreadCountClassesAndMethods( int cpu ) throws TestSetFailedException
+    public void everyThreadCountClassesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -585,7 +625,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void everyThreadCountAll( int cpu ) throws TestSetFailedException
+    public void everyThreadCountAll( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -609,7 +650,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void reusableThreadCountSuitesAndClasses( int cpu ) throws TestSetFailedException
+    public void reusableThreadCountSuitesAndClasses( int cpu )
+        throws TestSetFailedException
     {
         // 4 * cpu to 5 * cpu threads to run test classes
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
@@ -629,7 +671,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void reusableThreadCountSuitesAndMethods( int cpu ) throws TestSetFailedException
+    public void reusableThreadCountSuitesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         // 4 * cpu to 5 * cpu threads to run test methods
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
@@ -649,7 +692,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void reusableThreadCountClassesAndMethods( int cpu ) throws TestSetFailedException
+    public void reusableThreadCountClassesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         // 4 * cpu to 5 * cpu threads to run test methods
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
@@ -669,7 +713,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void reusableThreadCountAll( int cpu ) throws TestSetFailedException
+    public void reusableThreadCountAll( int cpu )
+        throws TestSetFailedException
     {
         // 8 * cpu to 13 * cpu threads to run test methods
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
@@ -690,7 +735,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void suites( int cpu ) throws TestSetFailedException
+    public void suites( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -708,7 +754,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void classes( int cpu ) throws TestSetFailedException
+    public void classes( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -726,7 +773,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void methods( int cpu ) throws TestSetFailedException
+    public void methods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -744,7 +792,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void suitesAndClasses( int cpu ) throws TestSetFailedException
+    public void suitesAndClasses( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -779,7 +828,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void suitesAndMethods( int cpu ) throws TestSetFailedException
+    public void suitesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -814,7 +864,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void classesAndMethods( int cpu ) throws TestSetFailedException
+    public void classesAndMethods( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -849,7 +900,8 @@ public final class ParallelComputerFactoryTest
     }
 
     @Theory
-    public void all( int cpu ) throws TestSetFailedException
+    public void all( int cpu )
+        throws TestSetFailedException
     {
         ParallelComputerFactory.overrideAvailableProcessors( cpu );
         Properties properties = new Properties();
@@ -898,10 +950,114 @@ public final class ParallelComputerFactoryTest
         assertThat( concurrency.methods, is( Integer.MAX_VALUE ) );
     }
 
-    private static Properties parallel( String parallel )
+    @Test
+    public void withoutShutdown()
+        throws TestSetFailedException, ExecutionException, InterruptedException
     {
         Properties properties = new Properties();
-        properties.setProperty( PARALLEL_KEY, parallel );
-        return properties;
+        properties.setProperty( PARALLEL_KEY, "methods" );
+        properties.setProperty( THREADCOUNTMETHODS_KEY, "2" );
+        JUnitCoreParameters params = new JUnitCoreParameters( properties );
+        ParallelComputer pc = createParallelComputer( params );
+
+        Result result = new JUnitCore().run( pc, TestClass.class );
+        long timeSpent = runtime.stop();
+        long deltaTime = 500L;
+
+        assertTrue( result.wasSuccessful() );
+        assertThat( result.getRunCount(), is( 3 ) );
+        assertThat( result.getFailureCount(), is( 0 ) );
+        assertThat( result.getIgnoreCount(), is( 0 ) );
+        assertEquals( 10000L, timeSpent, deltaTime );
+    }
+
+    @Test
+    public void shutdown()
+        throws TestSetFailedException, ExecutionException, InterruptedException
+    {
+        // The JUnitCore returns after 2.5s.
+        // The test-methods in TestClass are NOT interrupted, and return normally after 5s.
+        Properties properties = new Properties();
+        properties.setProperty( PARALLEL_KEY, "methods" );
+        properties.setProperty( THREADCOUNTMETHODS_KEY, "2" );
+        properties.setProperty( PARALLEL_TIMEOUT_KEY, Double.toString( 2.5d ) );
+        JUnitCoreParameters params = new JUnitCoreParameters( properties );
+        ParallelComputer pc = createParallelComputer( params );
+
+        new JUnitCore().run( pc, TestClass.class );
+        long timeSpent = runtime.stop();
+        long deltaTime = 500L;
+
+        assertEquals( 2500L, timeSpent, deltaTime );
+        assertTrue( pc.describeElapsedTimeout().contains(
+            "The test run has finished abruptly after timeout of 2.5 seconds." ) );
+        assertTrue( pc.describeElapsedTimeout().contains( TestClass.class.getName() ) );
+    }
+
+    @Test
+    public void forcedShutdown()
+        throws TestSetFailedException, ExecutionException, InterruptedException
+    {
+        // The JUnitCore returns after 2.5s, and the test-methods in TestClass are interrupted.
+        Properties properties = new Properties();
+        properties.setProperty( PARALLEL_KEY, "methods" );
+        properties.setProperty( THREADCOUNTMETHODS_KEY, "2" );
+        properties.setProperty( PARALLEL_TIMEOUTFORCED_KEY, Double.toString( 2.5d ) );
+        JUnitCoreParameters params = new JUnitCoreParameters( properties );
+        ParallelComputer pc = createParallelComputer( params );
+
+        new JUnitCore().run( pc, TestClass.class );
+        long timeSpent = runtime.stop();
+        long deltaTime = 500L;
+
+        assertEquals( 2500L, timeSpent, deltaTime );
+        assertTrue( pc.describeElapsedTimeout().contains(
+            "The test run has finished abruptly after timeout of 2.5 seconds." ) );
+        assertTrue( pc.describeElapsedTimeout().contains( TestClass.class.getName() ) );
+    }
+
+    public static class TestClass
+    {
+        @Test
+        public void a()
+            throws InterruptedException
+        {
+            long t1 = System.currentTimeMillis();
+            try{
+                Thread.sleep( 5000L );
+            }
+            finally
+            {
+                System.out.println( getClass().getSimpleName() + "#a() spent " + ( System.currentTimeMillis() - t1 ) );
+            }
+        }
+
+        @Test
+        public void b()
+            throws InterruptedException
+        {
+            long t1 = System.currentTimeMillis();
+            try{
+                Thread.sleep( 5000L );
+            }
+            finally
+            {
+                System.out.println( getClass().getSimpleName() + "#b() spent " + ( System.currentTimeMillis() - t1 ) );
+            }
+        }
+
+        @Test
+        public void c()
+            throws InterruptedException
+        {
+            long t1 = System.currentTimeMillis();
+            try{
+                Thread.sleep( 5000L );
+            }
+            finally
+            {
+                System.out.println( getClass().getSimpleName() + "#c() spent " + ( System.currentTimeMillis() - t1 ) );
+            }
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Stopwatch.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Stopwatch.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Stopwatch.java
new file mode 100644
index 0000000..558fc06
--- /dev/null
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Stopwatch.java
@@ -0,0 +1,46 @@
+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.rules.TestWatchman;
+import org.junit.runners.model.FrameworkMethod;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public final class Stopwatch
+    extends TestWatchman
+{
+    private long startNanos;
+
+    public long stop()
+    {
+        return TimeUnit.MILLISECONDS.convert( System.nanoTime() - startNanos, TimeUnit.NANOSECONDS );
+    }
+
+    @Override
+    public void starting( FrameworkMethod method )
+    {
+        startNanos = System.nanoTime();
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilderTest.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilderTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilderTest.java
index c34056a..4dda465 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilderTest.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilderTest.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.junitcore.pc;
  * under the License.
  */
 
+import org.apache.maven.surefire.junitcore.Stopwatch;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -48,97 +49,132 @@ import static org.apache.maven.surefire.junitcore.pc.RangeMatcher.between;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public class ParallelComputerBuilderTest {
+public class ParallelComputerBuilderTest
+{
+    private static volatile boolean beforeShutdown;
+
+    private static volatile Runnable shutdownTask;
+
     @Rule
     public final Stopwatch runtime = new Stopwatch();
 
+    private static void testKeepBeforeAfter( ParallelComputerBuilder builder, Class<?>... classes )
+    {
+        JUnitCore core = new JUnitCore();
+        for ( int round = 0; round < 5; round++ )
+        {
+            NothingDoingTest1.methods.clear();
+            Result result = core.run( builder.buildComputer(), classes );
+            assertTrue( result.wasSuccessful() );
+            Iterator<String> methods = NothingDoingTest1.methods.iterator();
+            for ( Class<?> clazz : classes )
+            {
+                String a = clazz.getName() + "#a()";
+                String b = clazz.getName() + "#b()";
+                assertThat( methods.next(), is( "init" ) );
+                assertThat( methods.next(), anyOf( is( a ), is( b ) ) );
+                assertThat( methods.next(), anyOf( is( a ), is( b ) ) );
+                assertThat( methods.next(), is( "deinit" ) );
+            }
+        }
+    }
+
     @Before
-    public void beforeTest() {
+    public void beforeTest()
+    {
         Class1.maxConcurrentMethods = 0;
         Class1.concurrentMethods = 0;
         shutdownTask = null;
     }
 
     @Test
-    public void parallelMethodsReuseOneOrTwoThreads() {
+    public void parallelMethodsReuseOneOrTwoThreads()
+    {
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.useOnePool(4);
+        parallelComputerBuilder.useOnePool( 4 );
 
         // One thread because one suite: TestSuite, however the capacity is 5.
-        parallelComputerBuilder.parallelSuites(5);
+        parallelComputerBuilder.parallelSuites( 5 );
 
         // Two threads because TestSuite has two classes, however the capacity is 5.
-        parallelComputerBuilder.parallelClasses(5);
+        parallelComputerBuilder.parallelClasses( 5 );
 
         // One or two threads because one threads comes from '#useOnePool(4)'
         // and next thread may be reused from finished class, however the capacity is 3.
-        parallelComputerBuilder.parallelMethods(3);
+        parallelComputerBuilder.parallelMethods( 3 );
 
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(0));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertFalse(computer.splitPool);
-        assertThat(computer.poolCapacity, is(4));
-        assertTrue(result.wasSuccessful());
-        if (Class1.maxConcurrentMethods == 1) {
-            assertThat(timeSpent, between(1950, 2250));
-        } else if (Class1.maxConcurrentMethods == 2) {
-            assertThat(timeSpent, between(1450, 1750));
-        } else {
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 0 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertFalse( computer.splitPool );
+        assertThat( computer.poolCapacity, is( 4 ) );
+        assertTrue( result.wasSuccessful() );
+        if ( Class1.maxConcurrentMethods == 1 )
+        {
+            assertThat( timeSpent, between( 1950, 2250 ) );
+        }
+        else if ( Class1.maxConcurrentMethods == 2 )
+        {
+            assertThat( timeSpent, between( 1450, 1750 ) );
+        }
+        else
+        {
             fail();
         }
     }
 
     @Test
-    public void suiteAndClassInOnePool() {
+    public void suiteAndClassInOnePool()
+    {
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.useOnePool(5);
-        parallelComputerBuilder.parallelSuites(5);
-        parallelComputerBuilder.parallelClasses(5);
-        parallelComputerBuilder.parallelMethods(3);
+        parallelComputerBuilder.useOnePool( 5 );
+        parallelComputerBuilder.parallelSuites( 5 );
+        parallelComputerBuilder.parallelClasses( 5 );
+        parallelComputerBuilder.parallelMethods( 3 );
 
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(1));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertFalse(computer.splitPool);
-        assertThat(computer.poolCapacity, is(5));
-        assertTrue(result.wasSuccessful());
-        assertThat(Class1.maxConcurrentMethods, is(2));
-        assertThat(timeSpent, anyOf(between(1450, 1750), between(1950, 2250), between(2450, 2750)));
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 1 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertFalse( computer.splitPool );
+        assertThat( computer.poolCapacity, is( 5 ) );
+        assertTrue( result.wasSuccessful() );
+        assertThat( Class1.maxConcurrentMethods, is( 2 ) );
+        assertThat( timeSpent, anyOf( between( 1450, 1750 ), between( 1950, 2250 ), between( 2450, 2750 ) ) );
     }
 
     @Test
-    public void onePoolWithUnlimitedParallelMethods() {
+    public void onePoolWithUnlimitedParallelMethods()
+    {
         // see ParallelComputerBuilder Javadoc
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.useOnePool(8);
-        parallelComputerBuilder.parallelSuites(2);
-        parallelComputerBuilder.parallelClasses(4);
+        parallelComputerBuilder.useOnePool( 8 );
+        parallelComputerBuilder.parallelSuites( 2 );
+        parallelComputerBuilder.parallelClasses( 4 );
         parallelComputerBuilder.parallelMethods();
 
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(1));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertFalse(computer.splitPool);
-        assertThat(computer.poolCapacity, is(8));
-        assertTrue(result.wasSuccessful());
-        assertThat(Class1.maxConcurrentMethods, is(4));
-        assertThat(timeSpent, between(950, 1250));
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 1 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertFalse( computer.splitPool );
+        assertThat( computer.poolCapacity, is( 8 ) );
+        assertTrue( result.wasSuccessful() );
+        assertThat( Class1.maxConcurrentMethods, is( 4 ) );
+        assertThat( timeSpent, between( 950, 1250 ) );
     }
 
     @Test
@@ -156,7 +192,7 @@ public class ParallelComputerBuilderTest {
         // One thread remains from '#useOnePool(3)'.
         parallelComputerBuilder.parallelMethods( 3 );
 
-        ParallelComputerBuilder.PC computer = ( ParallelComputerBuilder.PC ) parallelComputerBuilder.buildComputer();
+        ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
         Result result = new JUnitCore().run( computer, TestSuite.class );
         long timeSpent = runtime.stop();
 
@@ -172,265 +208,283 @@ public class ParallelComputerBuilderTest {
     }
 
     @Test
-    public void separatePoolsWithSuite() {
+    public void separatePoolsWithSuite()
+    {
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.parallelSuites(5);
-        parallelComputerBuilder.parallelClasses(5);
-        parallelComputerBuilder.parallelMethods(3);
+        parallelComputerBuilder.parallelSuites( 5 );
+        parallelComputerBuilder.parallelClasses( 5 );
+        parallelComputerBuilder.parallelMethods( 3 );
 
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(0));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertTrue(computer.splitPool);
-        assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
-        assertTrue(result.wasSuccessful());
-        assertThat(Class1.maxConcurrentMethods, is(3));
-        assertThat(timeSpent, between(950, 1250));
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 0 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertTrue( computer.splitPool );
+        assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
+        assertTrue( result.wasSuccessful() );
+        assertThat( Class1.maxConcurrentMethods, is( 3 ) );
+        assertThat( timeSpent, between( 950, 1250 ) );
     }
 
     @Test
-    public void separatePoolsWithSuiteAndClass() {
+    public void separatePoolsWithSuiteAndClass()
+    {
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.parallelSuites(5);
-        parallelComputerBuilder.parallelClasses(5);
-        parallelComputerBuilder.parallelMethods(3);
+        parallelComputerBuilder.parallelSuites( 5 );
+        parallelComputerBuilder.parallelClasses( 5 );
+        parallelComputerBuilder.parallelMethods( 3 );
 
         // 6 methods altogether.
         // 2 groups with 3 threads.
         // Each group takes 0.5s.
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(1));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertTrue(computer.splitPool);
-        assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
-        assertTrue(result.wasSuccessful());
-        assertThat(Class1.maxConcurrentMethods, is(3));
-        assertThat(timeSpent, between(950, 1250));
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 1 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertTrue( computer.splitPool );
+        assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
+        assertTrue( result.wasSuccessful() );
+        assertThat( Class1.maxConcurrentMethods, is( 3 ) );
+        assertThat( timeSpent, between( 950, 1250 ) );
     }
 
     @Test
-    public void separatePoolsWithSuiteAndSequentialClasses() {
+    public void separatePoolsWithSuiteAndSequentialClasses()
+    {
         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
-        parallelComputerBuilder.parallelSuites(5);
-        parallelComputerBuilder.parallelClasses(1);
-        parallelComputerBuilder.parallelMethods(3);
+        parallelComputerBuilder.parallelSuites( 5 );
+        parallelComputerBuilder.parallelClasses( 1 );
+        parallelComputerBuilder.parallelMethods( 3 );
 
         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-        Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
+        Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
         long timeSpent = runtime.stop();
 
-        assertThat(computer.suites.size(), is(1));
-        assertThat(computer.classes.size(), is(1));
-        assertThat(computer.nestedClasses.size(), is(2));
-        assertThat(computer.nestedSuites.size(), is(0));
-        assertTrue(computer.splitPool);
-        assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
-        assertTrue(result.wasSuccessful());
-        assertThat(Class1.maxConcurrentMethods, is(2));
-        assertThat(timeSpent, between(1450, 1750));
-    }
-
-    private static class ShutdownTest {
-        Result run(final boolean useInterrupt) {
-            ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder().useOnePool(8);
-            parallelComputerBuilder.parallelSuites(2);
-            parallelComputerBuilder.parallelClasses(3);
-            parallelComputerBuilder.parallelMethods(3);
-
-            final ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
-            shutdownTask = new Runnable() {
-                public void run() {
-                    Collection<org.junit.runner.Description> startedTests = computer.shutdown(useInterrupt);
-                    assertThat(startedTests.size(), is(not(0)));
-                }
-            };
-            return new JUnitCore().run(computer, TestSuite.class, Class2.class, Class3.class);
-        }
+        assertThat( computer.suites.size(), is( 1 ) );
+        assertThat( computer.classes.size(), is( 1 ) );
+        assertThat( computer.nestedClasses.size(), is( 2 ) );
+        assertThat( computer.nestedSuites.size(), is( 0 ) );
+        assertTrue( computer.splitPool );
+        assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
+        assertTrue( result.wasSuccessful() );
+        assertThat( Class1.maxConcurrentMethods, is( 2 ) );
+        assertThat( timeSpent, between( 1450, 1750 ) );
     }
 
-    @Test(timeout = 2000)
-    public void shutdown() {
-        Result result = new ShutdownTest().run(false);
+    @Test( timeout = 2000 )
+    public void shutdown()
+    {
+        Result result = new ShutdownTest().run( false );
         long timeSpent = runtime.stop();
-        assertTrue(result.wasSuccessful());
-        assertTrue(beforeShutdown);
-        assertThat(timeSpent, between(450, 1250));
+        assertTrue( result.wasSuccessful() );
+        assertTrue( beforeShutdown );
+        assertThat( timeSpent, between( 450, 1250 ) );
     }
 
-    @Test(timeout = 2000)
-    public void shutdownWithInterrupt() {
-        new ShutdownTest().run(true);
+    @Test( timeout = 2000 )
+    public void shutdownWithInterrupt()
+    {
+        new ShutdownTest().run( true );
         long timeSpent = runtime.stop();
-        assertTrue(beforeShutdown);
-        assertThat(timeSpent, between(450, 1250));
+        assertTrue( beforeShutdown );
+        assertThat( timeSpent, between( 450, 1250 ) );
     }
 
     @Test
-    public void nothingParallel() {
+    public void nothingParallel()
+    {
         JUnitCore core = new JUnitCore();
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
 
-        Result result = core.run(builder.buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class);
-        assertTrue(result.wasSuccessful());
-
-        result = core.run(builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
-        assertTrue(result.wasSuccessful());
+        Result result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class );
+        assertTrue( result.wasSuccessful() );
 
-        result = core.run(builder.useOnePool(1).buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class);
-        assertTrue(result.wasSuccessful());
+        result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
+        assertTrue( result.wasSuccessful() );
 
-        result = core.run(builder.useOnePool(1).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
-        assertTrue(result.wasSuccessful());
+        result = core.run( builder.useOnePool( 1 ).buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class );
+        assertTrue( result.wasSuccessful() );
 
-        result = core.run(builder.useOnePool(2).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
-        assertTrue(result.wasSuccessful());
+        result = core.run( builder.useOnePool( 1 ).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
+        assertTrue( result.wasSuccessful() );
 
-        Class<?>[] classes = {NothingDoingTest1.class, NothingDoingSuite.class};
+        result = core.run( builder.useOnePool( 2 ).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
+        assertTrue( result.wasSuccessful() );
 
-        result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses(1).buildComputer(), classes);
-        assertTrue(result.wasSuccessful());
+        Class<?>[] classes = { NothingDoingTest1.class, NothingDoingSuite.class };
 
-        result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses().buildComputer(), classes);
-        assertTrue(result.wasSuccessful());
+        result = core.run( builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses( 1 ).buildComputer(), classes );
+        assertTrue( result.wasSuccessful() );
 
-        classes = new Class<?>[]{NothingDoingSuite.class, NothingDoingSuite.class,
-                NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class};
+        result = core.run( builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses().buildComputer(), classes );
+        assertTrue( result.wasSuccessful() );
 
-        result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses(1).buildComputer(), classes);
-        assertTrue(result.wasSuccessful());
+        classes = new Class<?>[]{ NothingDoingSuite.class, NothingDoingSuite.class, NothingDoingTest1.class,
+            NothingDoingTest2.class, NothingDoingTest3.class };
 
-        result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses().buildComputer(), classes);
-        assertTrue(result.wasSuccessful());
-    }
+        result = core.run( builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses( 1 ).buildComputer(), classes );
+        assertTrue( result.wasSuccessful() );
 
-    private static void testKeepBeforeAfter(ParallelComputerBuilder builder, Class<?>... classes) {
-        JUnitCore core = new JUnitCore();
-        for (int round = 0; round < 5; round++) {
-            NothingDoingTest1.methods.clear();
-            Result result = core.run(builder.buildComputer(), classes);
-            assertTrue(result.wasSuccessful());
-            Iterator<String> methods = NothingDoingTest1.methods.iterator();
-            for (Class<?> clazz : classes) {
-                String a = clazz.getName() + "#a()";
-                String b = clazz.getName() + "#b()";
-                assertThat(methods.next(), is("init"));
-                assertThat(methods.next(), anyOf(is(a), is(b)));
-                assertThat(methods.next(), anyOf(is(a), is(b)));
-                assertThat(methods.next(), is("deinit"));
-            }
-        }
+        result = core.run( builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses().buildComputer(), classes );
+        assertTrue( result.wasSuccessful() );
     }
 
     @Test
-    public void keepBeforeAfterOneClass() {
+    public void keepBeforeAfterOneClass()
+    {
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
         builder.parallelMethods();
-        testKeepBeforeAfter(builder, NothingDoingTest1.class);
+        testKeepBeforeAfter( builder, NothingDoingTest1.class );
     }
 
     @Test
-    public void keepBeforeAfterTwoClasses() {
+    public void keepBeforeAfterTwoClasses()
+    {
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
-        builder.useOnePool(5).parallelClasses(1).parallelMethods(2);
-        testKeepBeforeAfter(builder, NothingDoingTest1.class, NothingDoingTest2.class);
+        builder.useOnePool( 5 ).parallelClasses( 1 ).parallelMethods( 2 );
+        testKeepBeforeAfter( builder, NothingDoingTest1.class, NothingDoingTest2.class );
     }
 
     @Test
-    public void keepBeforeAfterTwoParallelClasses() {
+    public void keepBeforeAfterTwoParallelClasses()
+    {
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
-        builder.useOnePool(8).parallelClasses(2).parallelMethods(2);
+        builder.useOnePool( 8 ).parallelClasses( 2 ).parallelMethods( 2 );
         JUnitCore core = new JUnitCore();
         NothingDoingTest1.methods.clear();
-        Class<?>[] classes = {NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class};
-        Result result = core.run(builder.buildComputer(), classes);
-        assertTrue(result.wasSuccessful());
-        ArrayList<String> methods = new ArrayList<String>(NothingDoingTest1.methods);
-        assertThat(methods.size(), is(12));
-        assertThat(methods.subList(9, 12), is(not(Arrays.asList("deinit", "deinit", "deinit"))));
+        Class<?>[] classes = { NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class };
+        Result result = core.run( builder.buildComputer(), classes );
+        assertTrue( result.wasSuccessful() );
+        ArrayList<String> methods = new ArrayList<String>( NothingDoingTest1.methods );
+        assertThat( methods.size(), is( 12 ) );
+        assertThat( methods.subList( 9, 12 ), is( not( Arrays.asList( "deinit", "deinit", "deinit" ) ) ) );
     }
 
-    private static volatile boolean beforeShutdown;
-    private static volatile Runnable shutdownTask;
+    private static class ShutdownTest
+    {
+        Result run( final boolean useInterrupt )
+        {
+            ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder().useOnePool( 8 );
+            parallelComputerBuilder.parallelSuites( 2 );
+            parallelComputerBuilder.parallelClasses( 3 );
+            parallelComputerBuilder.parallelMethods( 3 );
+
+            final ParallelComputerBuilder.PC computer =
+                (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
+            shutdownTask = new Runnable()
+            {
+                public void run()
+                {
+                    Collection<org.junit.runner.Description> startedTests = computer.shutdown( useInterrupt );
+                    assertThat( startedTests.size(), is( not( 0 ) ) );
+                }
+            };
+            return new JUnitCore().run( computer, TestSuite.class, Class2.class, Class3.class );
+        }
+    }
 
-    public static class Class1 {
+    public static class Class1
+    {
         static volatile int concurrentMethods = 0;
+
         static volatile int maxConcurrentMethods = 0;
 
         @Test
-        public void test1() throws InterruptedException {
-            synchronized (Class1.class) {
+        public void test1()
+            throws InterruptedException
+        {
+            synchronized ( Class1.class )
+            {
                 ++concurrentMethods;
-                Class1.class.wait(500);
-                maxConcurrentMethods = Math.max(maxConcurrentMethods, concurrentMethods--);
+                Class1.class.wait( 500 );
+                maxConcurrentMethods = Math.max( maxConcurrentMethods, concurrentMethods-- );
             }
         }
 
         @Test
-        public void test2() throws InterruptedException {
+        public void test2()
+            throws InterruptedException
+        {
             test1();
             Runnable shutdownTask = ParallelComputerBuilderTest.shutdownTask;
-            if (shutdownTask != null) {
+            if ( shutdownTask != null )
+            {
                 beforeShutdown = true;
                 shutdownTask.run();
             }
         }
     }
 
-    public static class Class2 extends Class1 {
-    }
-
-    public static class Class3 extends Class1 {
+    public static class Class2
+        extends Class1
+    {
     }
 
-    @RunWith(Suite.class)
-    @Suite.SuiteClasses({Class2.class, Class1.class})
-    public class TestSuite {
+    public static class Class3
+        extends Class1
+    {
     }
 
-    public static class NothingDoingTest1 {
+    public static class NothingDoingTest1
+    {
         static final Collection<String> methods = new ConcurrentLinkedQueue<String>();
 
         @BeforeClass
-        public static void init() {
-            methods.add("init");
+        public static void init()
+        {
+            methods.add( "init" );
         }
 
-        @Test
-        public void a() throws InterruptedException {
-            Thread.sleep(5);
-            methods.add(getClass().getName() + "#a()");
+        @AfterClass
+        public static void deinit()
+        {
+            methods.add( "deinit" );
         }
 
         @Test
-        public void b() throws InterruptedException {
-            Thread.sleep(5);
-            methods.add(getClass().getName() + "#b()");
+        public void a()
+            throws InterruptedException
+        {
+            Thread.sleep( 5 );
+            methods.add( getClass().getName() + "#a()" );
         }
 
-        @AfterClass
-        public static void deinit() {
-            methods.add("deinit");
+        @Test
+        public void b()
+            throws InterruptedException
+        {
+            Thread.sleep( 5 );
+            methods.add( getClass().getName() + "#b()" );
         }
     }
 
-    public static class NothingDoingTest2 extends NothingDoingTest1 {
+    public static class NothingDoingTest2
+        extends NothingDoingTest1
+    {
     }
 
-    public static class NothingDoingTest3 extends NothingDoingTest1 {
+    public static class NothingDoingTest3
+        extends NothingDoingTest1
+    {
     }
 
-    @RunWith(Suite.class)
-    @Suite.SuiteClasses({NothingDoingTest1.class, NothingDoingTest2.class})
-    public static class NothingDoingSuite {
+    @RunWith( Suite.class )
+    @Suite.SuiteClasses( { NothingDoingTest1.class, NothingDoingTest2.class } )
+    public static class NothingDoingSuite
+    {
+    }
+
+    @RunWith( Suite.class )
+    @Suite.SuiteClasses( { Class2.class, Class1.class } )
+    public class TestSuite
+    {
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/RangeMatcher.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/RangeMatcher.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/RangeMatcher.java
index ad04d6b..a71d853 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/RangeMatcher.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/RangeMatcher.java
@@ -27,9 +27,11 @@ import org.hamcrest.Matcher;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-final class RangeMatcher extends BaseMatcher<Long>
+final class RangeMatcher
+    extends BaseMatcher<Long>
 {
     private final long from;
+
     private final long to;
 
     private RangeMatcher( long from, long to )
@@ -38,14 +40,14 @@ final class RangeMatcher extends BaseMatcher<Long>
         this.to = to;
     }
 
-    public void describeTo( Description description )
+    public static Matcher<Long> between( long from, long to )
     {
-        description.appendValueList( "between ", " and ", "", from, to );
+        return new RangeMatcher( from, to );
     }
 
-    public static Matcher<Long> between( long from, long to )
+    public void describeTo( Description description )
     {
-        return new RangeMatcher( from, to );
+        description.appendValueList( "between ", " and ", "", from, to );
     }
 
     public boolean matches( Object o )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategiesTest.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategiesTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategiesTest.java
index 485b63c..d8d5d33 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategiesTest.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategiesTest.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.assertTrue;
 
 /**
  * Tests the factories in SchedulingStrategy.
- *
+ * <p/>
  * Th point of these tests is to check {@link Task#result} if changed
  * from <code>false</code> to <code>true</code> after all scheduled tasks
  * have finished.
@@ -38,118 +38,130 @@ import static org.junit.Assert.assertTrue;
  * Then {@link Task#result} should be asserted that is <code>true</code>.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see SchedulingStrategy
+ * @since 2.16
  */
-public class SchedulingStrategiesTest {
-    static class Task implements Runnable {
-        volatile boolean result = false;
-
-        public void run() {
-            result = true;
-        }
-    }
-
+public class SchedulingStrategiesTest
+{
     @Test
-    public void invokerStrategy() throws InterruptedException {
+    public void invokerStrategy()
+        throws InterruptedException
+    {
         SchedulingStrategy strategy = SchedulingStrategies.createInvokerStrategy();
-        assertFalse(strategy.hasSharedThreadPool());
-        assertTrue(strategy.canSchedule());
+        assertFalse( strategy.hasSharedThreadPool() );
+        assertTrue( strategy.canSchedule() );
 
         Task task = new Task();
 
-        strategy.schedule(task);
+        strategy.schedule( task );
 
-        assertTrue(strategy.canSchedule());
+        assertTrue( strategy.canSchedule() );
 
-        assertTrue(task.result);
+        assertTrue( task.result );
 
-        assertTrue(strategy.finished());
-        assertFalse(strategy.canSchedule());
+        assertTrue( strategy.finished() );
+        assertFalse( strategy.canSchedule() );
     }
 
     @Test
-    public void nonSharedPoolStrategy() throws InterruptedException {
-        SchedulingStrategy strategy = SchedulingStrategies.createParallelStrategy(2);
-        assertFalse(strategy.hasSharedThreadPool());
-        assertTrue(strategy.canSchedule());
+    public void nonSharedPoolStrategy()
+        throws InterruptedException
+    {
+        SchedulingStrategy strategy = SchedulingStrategies.createParallelStrategy( 2 );
+        assertFalse( strategy.hasSharedThreadPool() );
+        assertTrue( strategy.canSchedule() );
 
         Task task1 = new Task();
         Task task2 = new Task();
 
-        strategy.schedule(task1);
-        strategy.schedule(task2);
+        strategy.schedule( task1 );
+        strategy.schedule( task2 );
 
-        assertTrue(strategy.canSchedule());
+        assertTrue( strategy.canSchedule() );
 
-        assertTrue(strategy.finished());
-        assertFalse(strategy.canSchedule());
+        assertTrue( strategy.finished() );
+        assertFalse( strategy.canSchedule() );
 
-        assertTrue(task1.result);
-        assertTrue(task2.result);
+        assertTrue( task1.result );
+        assertTrue( task2.result );
     }
 
     @Test(expected = NullPointerException.class)
-    public void sharedPoolStrategyNullPool() {
-        SchedulingStrategies.createParallelSharedStrategy(null);
+    public void sharedPoolStrategyNullPool()
+    {
+        SchedulingStrategies.createParallelSharedStrategy( null );
     }
 
     @Test
-    public void sharedPoolStrategy() throws InterruptedException {
+    public void sharedPoolStrategy()
+        throws InterruptedException
+    {
         ExecutorService sharedPool = Executors.newCachedThreadPool();
 
-        SchedulingStrategy strategy1 = SchedulingStrategies.createParallelSharedStrategy(sharedPool);
-        assertTrue(strategy1.hasSharedThreadPool());
-        assertTrue(strategy1.canSchedule());
+        SchedulingStrategy strategy1 = SchedulingStrategies.createParallelSharedStrategy( sharedPool );
+        assertTrue( strategy1.hasSharedThreadPool() );
+        assertTrue( strategy1.canSchedule() );
 
-        SchedulingStrategy strategy2 = SchedulingStrategies.createParallelSharedStrategy(sharedPool);
-        assertTrue(strategy2.hasSharedThreadPool());
-        assertTrue(strategy2.canSchedule());
+        SchedulingStrategy strategy2 = SchedulingStrategies.createParallelSharedStrategy( sharedPool );
+        assertTrue( strategy2.hasSharedThreadPool() );
+        assertTrue( strategy2.canSchedule() );
 
         Task task1 = new Task();
         Task task2 = new Task();
         Task task3 = new Task();
         Task task4 = new Task();
 
-        strategy1.schedule(task1);
-        strategy2.schedule(task2);
-        strategy1.schedule(task3);
-        strategy2.schedule(task4);
+        strategy1.schedule( task1 );
+        strategy2.schedule( task2 );
+        strategy1.schedule( task3 );
+        strategy2.schedule( task4 );
 
-        assertTrue(strategy1.canSchedule());
-        assertTrue(strategy2.canSchedule());
+        assertTrue( strategy1.canSchedule() );
+        assertTrue( strategy2.canSchedule() );
 
-        assertTrue(strategy1.finished());
-        assertFalse(strategy1.canSchedule());
+        assertTrue( strategy1.finished() );
+        assertFalse( strategy1.canSchedule() );
 
-        assertTrue(strategy2.finished());
-        assertFalse(strategy2.canSchedule());
+        assertTrue( strategy2.finished() );
+        assertFalse( strategy2.canSchedule() );
 
-        assertTrue(task1.result);
-        assertTrue(task2.result);
-        assertTrue(task3.result);
-        assertTrue(task4.result);
+        assertTrue( task1.result );
+        assertTrue( task2.result );
+        assertTrue( task3.result );
+        assertTrue( task4.result );
     }
 
     @Test
-    public void infinitePoolStrategy() throws InterruptedException {
+    public void infinitePoolStrategy()
+        throws InterruptedException
+    {
         SchedulingStrategy strategy = SchedulingStrategies.createParallelStrategyUnbounded();
-        assertFalse(strategy.hasSharedThreadPool());
-        assertTrue(strategy.canSchedule());
+        assertFalse( strategy.hasSharedThreadPool() );
+        assertTrue( strategy.canSchedule() );
 
         Task task1 = new Task();
         Task task2 = new Task();
 
-        strategy.schedule(task1);
-        strategy.schedule(task2);
+        strategy.schedule( task1 );
+        strategy.schedule( task2 );
+
+        assertTrue( strategy.canSchedule() );
+
+        assertTrue( strategy.finished() );
+        assertFalse( strategy.canSchedule() );
 
-        assertTrue(strategy.canSchedule());
+        assertTrue( task1.result );
+        assertTrue( task2.result );
+    }
 
-        assertTrue(strategy.finished());
-        assertFalse(strategy.canSchedule());
+    static class Task
+        implements Runnable
+    {
+        volatile boolean result = false;
 
-        assertTrue(task1.result);
-        assertTrue(task2.result);
+        public void run()
+        {
+            result = true;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/Stopwatch.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/Stopwatch.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/Stopwatch.java
deleted file mode 100644
index 32b056c..0000000
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/pc/Stopwatch.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.maven.surefire.junitcore.pc;
-
-/*
- * 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.rules.TestWatchman;
-import org.junit.runners.model.FrameworkMethod;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Tibor Digana (tibor17)
- * @since 2.16
- */
-final class Stopwatch extends TestWatchman
-{
-    private long startNanos;
-
-    long stop()
-    {
-        return TimeUnit.MILLISECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
-    }
-
-    @Override
-    public void starting(FrameworkMethod method)
-    {
-        startNanos = System.nanoTime();
-    }
-}


[2/3] reformat code + IT + junit.apt.vm + fork-options-and-parllel-execution.apt.vm

Posted by ag...@apache.org.
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java
index 3937cd4..d7fe2d1 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java
@@ -23,27 +23,24 @@ import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
 import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 
+import java.util.concurrent.TimeUnit;
+
 /**
- * An algorithm which configures {@link ParallelComputer} with allocated thread resources by given {@link JUnitCoreParameters}.
+ * An algorithm which configures {@link ParallelComputer} with allocated thread resources by given
+ * {@link JUnitCoreParameters}.
  * The <code>AbstractSurefireMojo</code> has to provide correct combinations of thread-counts and <em>parallel</em>.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder
+ * @since 2.16
  */
 final class ParallelComputerFactory
 {
     private static int availableProcessors = Runtime.getRuntime().availableProcessors();
 
-    static class Concurrency
-    {
-        int suites, classes, methods, capacity;
-    }
-
     private ParallelComputerFactory()
     {
-        throw new IllegalStateException("Suppresses calling constructor, ensuring non-instantiability.");
+        throw new IllegalStateException( "Suppresses calling constructor, ensuring non-instantiability." );
     }
 
     /*
@@ -62,7 +59,8 @@ final class ParallelComputerFactory
         ParallelComputerFactory.availableProcessors = Runtime.getRuntime().availableProcessors();
     }
 
-    static ParallelComputer createParallelComputer( JUnitCoreParameters params ) throws TestSetFailedException
+    static ParallelComputer createParallelComputer( JUnitCoreParameters params )
+        throws TestSetFailedException
     {
         Concurrency concurrency = resolveConcurrency( params );
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
@@ -82,11 +80,14 @@ final class ParallelComputerFactory
             resolveMethodsConcurrency( builder, concurrency.methods );
         }
 
+        long timeout = secondsToNanos( params.getParallelTestsTimeoutInSeconds() );
+        long timeoutForced = secondsToNanos( params.getParallelTestsTimeoutForcedInSeconds() );
         resolveCapacity( builder, concurrency.capacity );
-        return builder.buildComputer();
+        return builder.buildComputer( timeout, timeoutForced, TimeUnit.NANOSECONDS );
     }
 
-    static Concurrency resolveConcurrency( JUnitCoreParameters params ) throws TestSetFailedException
+    static Concurrency resolveConcurrency( JUnitCoreParameters params )
+        throws TestSetFailedException
     {
         if ( !params.isAnyParallelitySelected() )
         {
@@ -96,9 +97,11 @@ final class ParallelComputerFactory
         if ( !params.isUseUnlimitedThreads() && !hasThreadCount( params ) && !hasThreadCounts( params ) )
         {
             throw new TestSetFailedException( "Unspecified thread-count(s). " +
-                    "See the parameters " + JUnitCoreParameters.USEUNLIMITEDTHREADS_KEY + ", "
-                    + JUnitCoreParameters.THREADCOUNT_KEY + ", " + JUnitCoreParameters.THREADCOUNTSUITES_KEY + ", "
-                    + JUnitCoreParameters.THREADCOUNTCLASSES_KEY + ", " + JUnitCoreParameters.THREADCOUNTMETHODS_KEY + ".");
+                                                  "See the parameters " + JUnitCoreParameters.USEUNLIMITEDTHREADS_KEY
+                                                  + ", " + JUnitCoreParameters.THREADCOUNT_KEY + ", "
+                                                  + JUnitCoreParameters.THREADCOUNTSUITES_KEY + ", "
+                                                  + JUnitCoreParameters.THREADCOUNTCLASSES_KEY + ", "
+                                                  + JUnitCoreParameters.THREADCOUNTMETHODS_KEY + "." );
         }
 
         if ( params.isUseUnlimitedThreads() )
@@ -111,9 +114,9 @@ final class ParallelComputerFactory
             {
                 if ( hasThreadCounts( params ) )
                 {
-                    return isLeafUnspecified( params ) ?
-                            concurrencyFromAllThreadCountsButUnspecifiedLeafCount( params ) :
-                            concurrencyFromAllThreadCounts( params );
+                    return isLeafUnspecified( params )
+                        ? concurrencyFromAllThreadCountsButUnspecifiedLeafCount( params )
+                        : concurrencyFromAllThreadCounts( params );
                 }
                 else
                 {
@@ -127,6 +130,12 @@ final class ParallelComputerFactory
         }
     }
 
+    private static long secondsToNanos( double seconds )
+    {
+        double nanos = seconds > 0 ? seconds * 1E9 : 0;
+        return Double.isInfinite( nanos ) || nanos >= Long.MAX_VALUE ? 0 : (long) nanos;
+    }
+
     private static void resolveSuitesConcurrency( ParallelComputerBuilder builder, int concurrency )
     {
         if ( concurrency > 0 )
@@ -242,14 +251,14 @@ final class ParallelComputerFactory
         concurrency.capacity = params.getThreadCount();
         double all = sumThreadCounts( concurrency );
 
-        concurrency.suites = params.isParallelSuites() ?
-                multiplyByCoreCount( params, concurrency.capacity * ( concurrency.suites / all ) ) : 0;
+        concurrency.suites = params.isParallelSuites() ? multiplyByCoreCount( params, concurrency.capacity * (
+            concurrency.suites / all ) ) : 0;
 
-        concurrency.classes = params.isParallelClasses() ?
-                multiplyByCoreCount( params, concurrency.capacity * ( concurrency.classes / all ) ) : 0;
+        concurrency.classes = params.isParallelClasses() ? multiplyByCoreCount( params, concurrency.capacity * (
+            concurrency.classes / all ) ) : 0;
 
-        concurrency.methods = params.isParallelMethod() ?
-                multiplyByCoreCount( params, concurrency.capacity * ( concurrency.methods / all ) ) : 0;
+        concurrency.methods = params.isParallelMethod() ? multiplyByCoreCount( params, concurrency.capacity * (
+            concurrency.methods / all ) ) : 0;
 
         concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
         adjustPrecisionInLeaf( params, concurrency );
@@ -261,7 +270,7 @@ final class ParallelComputerFactory
         Concurrency concurrency = new Concurrency();
         concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0;
         concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0;
-        concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0 ;
+        concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0;
         concurrency.capacity = (int) Math.min( sumThreadCounts( concurrency ), Integer.MAX_VALUE );
         return concurrency;
     }
@@ -269,9 +278,20 @@ final class ParallelComputerFactory
     private static int countParallelEntities( JUnitCoreParameters params )
     {
         int count = 0;
-        if ( params.isParallelSuites() ) count++;
-        if ( params.isParallelClasses() ) count++;
-        if ( params.isParallelMethod() ) count++;
+        if ( params.isParallelSuites() )
+        {
+            count++;
+        }
+
+        if ( params.isParallelClasses() )
+        {
+            count++;
+        }
+
+        if ( params.isParallelMethod() )
+        {
+            count++;
+        }
         return count;
     }
 
@@ -301,14 +321,23 @@ final class ParallelComputerFactory
 
     private static void setLeafInfinite( JUnitCoreParameters params, Concurrency concurrency )
     {
-        if ( params.isParallelMethod() ) concurrency.methods = Integer.MAX_VALUE;
-        else if ( params.isParallelClasses() ) concurrency.classes = Integer.MAX_VALUE;
-        else if ( params.isParallelSuites() ) concurrency.suites = Integer.MAX_VALUE;
+        if ( params.isParallelMethod() )
+        {
+            concurrency.methods = Integer.MAX_VALUE;
+        }
+        else if ( params.isParallelClasses() )
+        {
+            concurrency.classes = Integer.MAX_VALUE;
+        }
+        else if ( params.isParallelSuites() )
+        {
+            concurrency.suites = Integer.MAX_VALUE;
+        }
     }
 
     private static boolean isLeafUnspecified( JUnitCoreParameters params )
     {
-        int maskOfParallel = params.isParallelSuites() ? 4: 0;
+        int maskOfParallel = params.isParallelSuites() ? 4 : 0;
         maskOfParallel |= params.isParallelClasses() ? 2 : 0;
         maskOfParallel |= params.isParallelMethod() ? 1 : 0;
 
@@ -333,11 +362,11 @@ final class ParallelComputerFactory
     private static boolean hasThreadCounts( JUnitCoreParameters jUnitCoreParameters )
     {
         return jUnitCoreParameters.getThreadCountSuites() > 0 ||
-                jUnitCoreParameters.getThreadCountClasses() > 0 ||
-                jUnitCoreParameters.getThreadCountMethods() > 0;
+            jUnitCoreParameters.getThreadCountClasses() > 0 ||
+            jUnitCoreParameters.getThreadCountMethods() > 0;
     }
 
-    private static boolean hasThreadCount ( JUnitCoreParameters jUnitCoreParameters )
+    private static boolean hasThreadCount( JUnitCoreParameters jUnitCoreParameters )
     {
         return jUnitCoreParameters.getThreadCount() > 0;
     }
@@ -360,9 +389,13 @@ final class ParallelComputerFactory
     private static int multiplyByCoreCount( JUnitCoreParameters jUnitCoreParameters, double threadsPerCore )
     {
         double numberOfThreads =
-                    jUnitCoreParameters.isPerCoreThreadCount() ?
-                            threadsPerCore * (double) availableProcessors : threadsPerCore;
+            jUnitCoreParameters.isPerCoreThreadCount() ? threadsPerCore * (double) availableProcessors : threadsPerCore;
 
         return numberOfThreads > 0 ? (int) Math.min( numberOfThreads, Integer.MAX_VALUE ) : Integer.MAX_VALUE;
     }
+
+    static class Concurrency
+    {
+        int suites, classes, methods, capacity;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/AbstractThreadPoolStrategy.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/AbstractThreadPoolStrategy.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/AbstractThreadPoolStrategy.java
index fea0701..56621d5 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/AbstractThreadPoolStrategy.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/AbstractThreadPoolStrategy.java
@@ -31,81 +31,103 @@ import java.util.concurrent.atomic.AtomicBoolean;
  * depending if the thread pool is shared with other strategies or not.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see SchedulingStrategy
  * @see SharedThreadPoolStrategy
  * @see NonSharedThreadPoolStrategy
+ * @since 2.16
  */
-abstract class AbstractThreadPoolStrategy extends SchedulingStrategy {
+abstract class AbstractThreadPoolStrategy
+    extends SchedulingStrategy
+{
     private final ExecutorService threadPool;
+
     private final Collection<Future<?>> futureResults;
-    private final AtomicBoolean canSchedule = new AtomicBoolean(true);
 
-    AbstractThreadPoolStrategy(ExecutorService threadPool) {
-        this(threadPool, null);
+    private final AtomicBoolean canSchedule = new AtomicBoolean( true );
+
+    AbstractThreadPoolStrategy( ExecutorService threadPool )
+    {
+        this( threadPool, null );
     }
 
-    AbstractThreadPoolStrategy(ExecutorService threadPool, Collection<Future<?>> futureResults) {
+    AbstractThreadPoolStrategy( ExecutorService threadPool, Collection<Future<?>> futureResults )
+    {
         this.threadPool = threadPool;
         this.futureResults = futureResults;
     }
 
-    protected final ExecutorService getThreadPool() {
+    protected final ExecutorService getThreadPool()
+    {
         return threadPool;
     }
 
-    protected final Collection<Future<?>> getFutureResults() {
+    protected final Collection<Future<?>> getFutureResults()
+    {
         return futureResults;
     }
 
-    protected final void disable() {
-        canSchedule.set(false);
+    protected final void disable()
+    {
+        canSchedule.set( false );
     }
 
     @Override
-    public void schedule(Runnable task) {
-        if (canSchedule()) {
-            Future<?> futureResult = threadPool.submit(task);
-            if (futureResults != null) {
-                futureResults.add(futureResult);
+    public void schedule( Runnable task )
+    {
+        if ( canSchedule() )
+        {
+            Future<?> futureResult = threadPool.submit( task );
+            if ( futureResults != null )
+            {
+                futureResults.add( futureResult );
             }
         }
     }
 
     @Override
-    protected boolean stop() {
-        boolean wasRunning = canSchedule.getAndSet(false);
-        if (threadPool.isShutdown()) {
+    protected boolean stop()
+    {
+        boolean wasRunning = canSchedule.getAndSet( false );
+        if ( threadPool.isShutdown() )
+        {
             wasRunning = false;
-        } else {
+        }
+        else
+        {
             threadPool.shutdown();
         }
         return wasRunning;
     }
 
     @Override
-    protected boolean stopNow() {
-        boolean wasRunning = canSchedule.getAndSet(false);
-        if (threadPool.isShutdown()) {
+    protected boolean stopNow()
+    {
+        boolean wasRunning = canSchedule.getAndSet( false );
+        if ( threadPool.isShutdown() )
+        {
             wasRunning = false;
-        } else {
+        }
+        else
+        {
             threadPool.shutdownNow();
         }
         return wasRunning;
     }
 
     @Override
-    protected void setDefaultShutdownHandler(Scheduler.ShutdownHandler handler) {
-        if (threadPool instanceof ThreadPoolExecutor) {
+    protected void setDefaultShutdownHandler( Scheduler.ShutdownHandler handler )
+    {
+        if ( threadPool instanceof ThreadPoolExecutor )
+        {
             ThreadPoolExecutor pool = (ThreadPoolExecutor) threadPool;
-            handler.setRejectedExecutionHandler(pool.getRejectedExecutionHandler());
-            pool.setRejectedExecutionHandler(handler);
+            handler.setRejectedExecutionHandler( pool.getRejectedExecutionHandler() );
+            pool.setRejectedExecutionHandler( handler );
         }
     }
 
     @Override
-    public final boolean canSchedule() {
+    public final boolean canSchedule()
+    {
         return canSchedule.get();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Balancer.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Balancer.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Balancer.java
index 1b28309..2277bd4 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Balancer.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Balancer.java
@@ -22,7 +22,7 @@ package org.apache.maven.surefire.junitcore.pc;
 /**
  * The Balancer controls the maximum of concurrent threads in the current Scheduler(s) and prevents
  * from own thread resources exhaustion if other group of schedulers share the same pool of threads.
- * <p>
+ * <p/>
  * If a permit is available, {@link #acquirePermit()} simply returns and a new test is scheduled
  * by {@link Scheduler#schedule(Runnable)} in the current runner. Otherwise waiting for a release.
  * One permit is released as soon as the child thread has finished.
@@ -30,7 +30,8 @@ package org.apache.maven.surefire.junitcore.pc;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public interface Balancer {
+public interface Balancer
+{
 
     /**
      * Acquires a permit from this balancer, blocking until one is available.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/BalancerFactory.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/BalancerFactory.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/BalancerFactory.java
index e7db197..e4c36e3 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/BalancerFactory.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/BalancerFactory.java
@@ -21,11 +21,11 @@ package org.apache.maven.surefire.junitcore.pc;
 
 /**
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see Balancer
+ * @since 2.16
  */
-public class BalancerFactory {
+public class BalancerFactory
+{
     private BalancerFactory()
     {
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/InvokerStrategy.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/InvokerStrategy.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/InvokerStrategy.java
index dc1e5b3..29a6624 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/InvokerStrategy.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/InvokerStrategy.java
@@ -25,37 +25,45 @@ import java.util.concurrent.atomic.AtomicBoolean;
  * The sequentially executing strategy in private package.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see SchedulingStrategy
+ * @since 2.16
  */
-final class InvokerStrategy extends SchedulingStrategy {
-    private final AtomicBoolean canSchedule = new AtomicBoolean(true);
+final class InvokerStrategy
+    extends SchedulingStrategy
+{
+    private final AtomicBoolean canSchedule = new AtomicBoolean( true );
 
     @Override
-    public void schedule(Runnable task) {
-        if (canSchedule()) {
+    public void schedule( Runnable task )
+    {
+        if ( canSchedule() )
+        {
             task.run();
         }
     }
 
     @Override
-    protected boolean stop() {
-        return canSchedule.getAndSet(false);
+    protected boolean stop()
+    {
+        return canSchedule.getAndSet( false );
     }
 
     @Override
-    public boolean hasSharedThreadPool() {
+    public boolean hasSharedThreadPool()
+    {
         return false;
     }
 
     @Override
-    public boolean canSchedule() {
+    public boolean canSchedule()
+    {
         return canSchedule.get();
     }
 
     @Override
-    public boolean finished() throws InterruptedException {
+    public boolean finished()
+        throws InterruptedException
+    {
         return stop();
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NonSharedThreadPoolStrategy.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NonSharedThreadPoolStrategy.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NonSharedThreadPoolStrategy.java
index b463605..df80ad9 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NonSharedThreadPoolStrategy.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NonSharedThreadPoolStrategy.java
@@ -26,28 +26,36 @@ import java.util.concurrent.TimeUnit;
  * Parallel strategy for non-shared thread pool in private package.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see AbstractThreadPoolStrategy
+ * @since 2.16
  */
-final class NonSharedThreadPoolStrategy extends AbstractThreadPoolStrategy {
-    NonSharedThreadPoolStrategy(ExecutorService threadPool) {
-        super(threadPool);
+final class NonSharedThreadPoolStrategy
+    extends AbstractThreadPoolStrategy
+{
+    NonSharedThreadPoolStrategy( ExecutorService threadPool )
+    {
+        super( threadPool );
     }
 
     @Override
-    public boolean hasSharedThreadPool() {
+    public boolean hasSharedThreadPool()
+    {
         return false;
     }
 
     @Override
-    public boolean finished() throws InterruptedException {
+    public boolean finished()
+        throws InterruptedException
+    {
         boolean wasRunning = canSchedule();
         getThreadPool().shutdown();
-        try {
-            getThreadPool().awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+        try
+        {
+            getThreadPool().awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS );
             return wasRunning;
-        } finally {
+        }
+        finally
+        {
             disable();
         }
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NullBalancer.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NullBalancer.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NullBalancer.java
index eec3759..56b9522 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NullBalancer.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/NullBalancer.java
@@ -23,11 +23,11 @@ package org.apache.maven.surefire.junitcore.pc;
  * This balancer implements {@link Balancer} and does not do anything -no blocking operation.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see Balancer
+ * @since 2.16
  */
-final class NullBalancer implements Balancer
+final class NullBalancer
+    implements Balancer
 {
     public boolean acquirePermit()
     {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputer.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputer.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputer.java
index ef4fc94..242df2e 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputer.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputer.java
@@ -19,10 +19,13 @@ package org.apache.maven.surefire.junitcore.pc;
  * under the License.
  */
 
+import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.junit.runner.Computer;
 import org.junit.runner.Description;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.TreeSet;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -33,16 +36,77 @@ import java.util.concurrent.TimeUnit;
  * ParallelComputer extends JUnit {@link Computer} and has a shutdown functionality.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see ParallelComputerBuilder
+ * @since 2.16
  */
-public abstract class ParallelComputer extends Computer
+public abstract class ParallelComputer
+    extends Computer
 {
+    private final long timeoutNanos;
+
+    private final long timeoutForcedNanos;
+
     private ScheduledExecutorService shutdownScheduler;
 
+    private Future<Collection<Description>> testsBeforeShutdown;
+
+    private Future<Collection<Description>> testsBeforeForcedShutdown;
+
+    public ParallelComputer( long timeout, long timeoutForced, TimeUnit timeoutUnit )
+    {
+        this.timeoutNanos = timeoutUnit.toNanos( timeout );
+        this.timeoutForcedNanos = timeoutUnit.toNanos( timeoutForced );
+    }
+
+    private static long minTimeout( long timeout1, long timeout2 )
+    {
+        if ( timeout1 == 0 )
+        {
+            return timeout2;
+        }
+        else if ( timeout2 == 0 )
+        {
+            return timeout1;
+        }
+        else
+        {
+            return Math.min( timeout1, timeout2 );
+        }
+    }
+
+    private static Collection<String> printShutdownHook( Future<Collection<Description>> future )
+        throws TestSetFailedException
+    {
+        if ( !future.isCancelled() && future.isDone() )
+        {
+            try
+            {
+                TreeSet<String> executedTests = new TreeSet<String>();
+                for ( Description executedTest : future.get() )
+                {
+                    if ( executedTest != null && executedTest.getDisplayName() != null )
+                    {
+                        executedTests.add( executedTest.getDisplayName() );
+                    }
+                }
+                return executedTests;
+            }
+            catch ( Exception e )
+            {
+                throw new TestSetFailedException( e );
+            }
+        }
+        return Collections.emptySet();
+    }
+
     public abstract Collection<Description> shutdown( boolean shutdownNow );
 
+    protected final void beforeRunQuietly()
+    {
+        testsBeforeShutdown = timeoutNanos > 0 ? scheduleShutdown() : null;
+        testsBeforeForcedShutdown = timeoutForcedNanos > 0 ? scheduleForcedShutdown() : null;
+    }
+
     protected final void afterRunQuietly()
     {
         if ( shutdownScheduler != null )
@@ -51,14 +115,43 @@ public abstract class ParallelComputer extends Computer
         }
     }
 
-    public Future<Collection<Description>> scheduleShutdown( int timeout, TimeUnit unit )
+    public String describeElapsedTimeout()
+        throws TestSetFailedException
     {
-        return getShutdownScheduler().schedule( createShutdownTask( false ), timeout, unit );
+        TreeSet<String> executedTests = new TreeSet<String>();
+        if ( testsBeforeShutdown != null )
+        {
+            executedTests.addAll( printShutdownHook( testsBeforeShutdown ) );
+        }
+
+        if ( testsBeforeForcedShutdown != null )
+        {
+            executedTests.addAll( printShutdownHook( testsBeforeForcedShutdown ) );
+        }
+
+        StringBuilder msg = new StringBuilder();
+        if ( !executedTests.isEmpty() )
+        {
+            msg.append( "The test run has finished abruptly after timeout of " );
+            msg.append( nanosToSeconds( minTimeout( timeoutNanos, timeoutForcedNanos ) ) );
+            msg.append( " seconds.\n" );
+            msg.append( "These tests were executed in prior of the shutdown operation:\n" );
+            for ( String executedTest : executedTests )
+            {
+                msg.append( executedTest ).append( '\n' );
+            }
+        }
+        return msg.toString();
     }
 
-    public Future<Collection<Description>> scheduleForcedShutdown( int timeout, TimeUnit unit )
+    private Future<Collection<Description>> scheduleShutdown()
     {
-        return getShutdownScheduler().schedule( createShutdownTask( true ), timeout, unit );
+        return getShutdownScheduler().schedule( createShutdownTask( false ), timeoutNanos, TimeUnit.NANOSECONDS );
+    }
+
+    private Future<Collection<Description>> scheduleForcedShutdown()
+    {
+        return getShutdownScheduler().schedule( createShutdownTask( true ), timeoutForcedNanos, TimeUnit.NANOSECONDS );
     }
 
     private ScheduledExecutorService getShutdownScheduler()
@@ -74,10 +167,16 @@ public abstract class ParallelComputer extends Computer
     {
         return new Callable<Collection<Description>>()
         {
-            public Collection<Description> call() throws Exception
+            public Collection<Description> call()
+                throws Exception
             {
-                return shutdown( isForced );
+                return ParallelComputer.this.shutdown( isForced );
             }
         };
     }
+
+    private double nanosToSeconds( long nanos )
+    {
+        return (double) nanos / 1E9;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilder.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilder.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilder.java
index ef2c05e..8e7f5b0 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilder.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ParallelComputerBuilder.java
@@ -39,6 +39,7 @@ import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Executing suites, classes and methods with defined concurrency. In this example the threads which completed
@@ -51,9 +52,11 @@ import java.util.concurrent.Executors;
  * new JUnitCore().run(computer, tests);
  * </pre>
  * Note that the type has always at least one thread even if unspecified. The capacity in
- * {@link ParallelComputerBuilder#useOnePool(int)} must be greater than the number of concurrent suites and classes altogether.
- * <p>
- * The Computer can be shutdown in a separate thread. Pending tests will be interrupted if the argument is <tt>true</tt>.
+ * {@link ParallelComputerBuilder#useOnePool(int)} must be greater than the number of concurrent suites and classes
+ * altogether.
+ * <p/>
+ * The Computer can be shutdown in a separate thread. Pending tests will be interrupted if the argument is
+ * <tt>true</tt>.
  * <pre>
  * computer.shutdown(true);
  * </pre>
@@ -61,33 +64,36 @@ import java.util.concurrent.Executors;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public class ParallelComputerBuilder {
-    private static enum Type {
-        SUITES, CLASSES, METHODS
-    }
-
+public class ParallelComputerBuilder
+{
     static final int TOTAL_POOL_SIZE_UNDEFINED = 0;
-    private final Map<Type, Integer> parallelGroups = new HashMap<Type, Integer>(3);
+
+    private final Map<Type, Integer> parallelGroups = new HashMap<Type, Integer>( 3 );
+
     private boolean useSeparatePools;
+
     private int totalPoolSize;
 
     /**
      * Calling {@link #useSeparatePools()}.
      */
-    public ParallelComputerBuilder() {
+    public ParallelComputerBuilder()
+    {
         useSeparatePools();
-        parallelGroups.put(Type.SUITES, 0);
-        parallelGroups.put(Type.CLASSES, 0);
-        parallelGroups.put(Type.METHODS, 0);
+        parallelGroups.put( Type.SUITES, 0 );
+        parallelGroups.put( Type.CLASSES, 0 );
+        parallelGroups.put( Type.METHODS, 0 );
     }
 
-    public ParallelComputerBuilder useSeparatePools() {
+    public ParallelComputerBuilder useSeparatePools()
+    {
         totalPoolSize = TOTAL_POOL_SIZE_UNDEFINED;
         useSeparatePools = true;
         return this;
     }
 
-    public ParallelComputerBuilder useOnePool() {
+    public ParallelComputerBuilder useOnePool()
+    {
         totalPoolSize = TOTAL_POOL_SIZE_UNDEFINED;
         useSeparatePools = false;
         return this;
@@ -95,99 +101,140 @@ public class ParallelComputerBuilder {
 
     /**
      * @param totalPoolSize Pool size where suites, classes and methods are executed in parallel.
-     *                      If the <tt>totalPoolSize</tt> is {@link Integer#MAX_VALUE}, the pool capacity is not limited.
+     *                      If the <tt>totalPoolSize</tt> is {@link Integer#MAX_VALUE}, the pool capacity is not
+     *                      limited.
      * @throws IllegalArgumentException If <tt>totalPoolSize</tt> is &lt; 1.
      */
-    public ParallelComputerBuilder useOnePool(int totalPoolSize) {
-        if (totalPoolSize < 1) {
-            throw new IllegalArgumentException("Size of common pool is less than 1.");
+    public ParallelComputerBuilder useOnePool( int totalPoolSize )
+    {
+        if ( totalPoolSize < 1 )
+        {
+            throw new IllegalArgumentException( "Size of common pool is less than 1." );
         }
         this.totalPoolSize = totalPoolSize;
         useSeparatePools = false;
         return this;
     }
 
-    public ParallelComputerBuilder parallelSuites() {
-        return parallel(Type.SUITES);
+    public ParallelComputerBuilder parallelSuites()
+    {
+        return parallel( Type.SUITES );
     }
 
-    public ParallelComputerBuilder parallelSuites(int nThreads) {
-        return parallel(nThreads, Type.SUITES);
+    public ParallelComputerBuilder parallelSuites( int nThreads )
+    {
+        return parallel( nThreads, Type.SUITES );
     }
 
-    public ParallelComputerBuilder parallelClasses() {
-        return parallel(Type.CLASSES);
+    public ParallelComputerBuilder parallelClasses()
+    {
+        return parallel( Type.CLASSES );
     }
 
-    public ParallelComputerBuilder parallelClasses(int nThreads) {
-        return parallel(nThreads, Type.CLASSES);
+    public ParallelComputerBuilder parallelClasses( int nThreads )
+    {
+        return parallel( nThreads, Type.CLASSES );
     }
 
-    public ParallelComputerBuilder parallelMethods() {
-        return parallel(Type.METHODS);
+    public ParallelComputerBuilder parallelMethods()
+    {
+        return parallel( Type.METHODS );
     }
 
-    public ParallelComputerBuilder parallelMethods(int nThreads) {
-        return parallel(nThreads, Type.METHODS);
+    public ParallelComputerBuilder parallelMethods( int nThreads )
+    {
+        return parallel( nThreads, Type.METHODS );
     }
 
-    private ParallelComputerBuilder parallel(int nThreads, Type parallelType) {
-        if (nThreads < 0) {
-            throw new IllegalArgumentException("negative nThreads " + nThreads);
+    private ParallelComputerBuilder parallel( int nThreads, Type parallelType )
+    {
+        if ( nThreads < 0 )
+        {
+            throw new IllegalArgumentException( "negative nThreads " + nThreads );
         }
 
-        if (parallelType == null) {
-            throw new NullPointerException("null parallelType");
+        if ( parallelType == null )
+        {
+            throw new NullPointerException( "null parallelType" );
         }
 
-        parallelGroups.put(parallelType, nThreads);
+        parallelGroups.put( parallelType, nThreads );
         return this;
     }
 
-    private ParallelComputerBuilder parallel(Type parallelType) {
-        return parallel(Integer.MAX_VALUE, parallelType);
+    private ParallelComputerBuilder parallel( Type parallelType )
+    {
+        return parallel( Integer.MAX_VALUE, parallelType );
+    }
+
+    public ParallelComputer buildComputer()
+    {
+        return buildComputer( 0, 0, TimeUnit.NANOSECONDS );
     }
 
-    public ParallelComputer buildComputer() {
-        return new PC();
+    public ParallelComputer buildComputer( long timeout, long timeoutForced, TimeUnit timeUnit )
+    {
+        return new PC( timeout, timeoutForced, timeUnit );
     }
 
-    final class PC extends ParallelComputer
+    private static enum Type
+    {
+        SUITES,
+        CLASSES,
+        METHODS
+    }
+
+    final class PC
+        extends ParallelComputer
     {
         final Collection<ParentRunner> suites = new LinkedHashSet<ParentRunner>();
+
         final Collection<ParentRunner> nestedSuites = new LinkedHashSet<ParentRunner>();
+
         final Collection<ParentRunner> classes = new LinkedHashSet<ParentRunner>();
+
         final Collection<ParentRunner> nestedClasses = new LinkedHashSet<ParentRunner>();
+
         final Collection<Runner> unscheduledRunners = new LinkedHashSet<Runner>();
+
         final int poolCapacity;
+
         final boolean splitPool;
+
         private final Map<Type, Integer> allGroups;
+
         private volatile Scheduler master;
 
-        private PC() {
-            allGroups = new HashMap<Type, Integer>(ParallelComputerBuilder.this.parallelGroups);
+        private PC( long timeout, long timeoutForced, TimeUnit timeoutUnit )
+        {
+            super( timeout, timeoutForced, timeoutUnit );
+            allGroups = new HashMap<Type, Integer>( ParallelComputerBuilder.this.parallelGroups );
             poolCapacity = ParallelComputerBuilder.this.totalPoolSize;
             splitPool = ParallelComputerBuilder.this.useSeparatePools;
         }
 
         @Override
-        public Collection<Description> shutdown(boolean shutdownNow) {
+        public Collection<Description> shutdown( boolean shutdownNow )
+        {
             final Scheduler master = this.master;
-            return master == null ? Collections.<Description>emptyList() : master.shutdown(shutdownNow);
+            return master == null ? Collections.<Description>emptyList() : master.shutdown( shutdownNow );
         }
 
         @Override
-        public Runner getSuite(RunnerBuilder builder, Class<?>[] cls) throws InitializationError {
-            super.getSuite(builder, cls);
+        public Runner getSuite( RunnerBuilder builder, Class<?>[] cls )
+            throws InitializationError
+        {
+            super.getSuite( builder, cls );
             populateChildrenFromSuites();
             return setSchedulers();
         }
 
         @Override
-        protected Runner getRunner( RunnerBuilder builder, Class<?> testClass ) throws Throwable
+        protected Runner getRunner( RunnerBuilder builder, Class<?> testClass )
+            throws Throwable
         {
             Runner runner = super.getRunner( builder, testClass );
-            if ( canSchedule(runner) )
+            if ( canSchedule( runner ) )
             {
                 if ( runner instanceof Suite )
                 {
@@ -205,29 +252,9 @@ public class ParallelComputerBuilder {
             return runner;
         }
 
-        private class SuiteFilter extends Filter {
-            @Override
-            public boolean shouldRun(Description description) {
-                return true;
-            }
-
-            @Override
-            public void apply(Object child) throws NoTestsRemainException {
-                super.apply(child);
-                if (child instanceof Suite) {
-                    nestedSuites.add((Suite) child);
-                } else if (child instanceof ParentRunner) {
-                    nestedClasses.add((ParentRunner) child);
-                }
-            }
-
-            @Override
-            public String describe() {
-                return "";
-            }
-        }
-
-        private <T extends Runner> ParentRunner wrapRunners( Collection<T> runners ) throws InitializationError {
+        private <T extends Runner> ParentRunner wrapRunners( Collection<T> runners )
+            throws InitializationError
+        {
             ArrayList<Runner> runs = new ArrayList<Runner>();
             for ( T runner : runners )
             {
@@ -237,7 +264,9 @@ public class ParallelComputerBuilder {
                 }
             }
 
-            return runs.isEmpty() ? null : new Suite( null, runs ) {};
+            return runs.isEmpty() ? null : new Suite( null, runs )
+            {
+            };
         }
 
         private boolean hasChildren( Runner runner )
@@ -247,59 +276,83 @@ public class ParallelComputerBuilder {
             return children != null && !children.isEmpty();
         }
 
-        private ExecutorService createPool(int poolSize) {
-            return poolSize < Integer.MAX_VALUE ? Executors.newFixedThreadPool(poolSize) : Executors.newCachedThreadPool();
+        private ExecutorService createPool( int poolSize )
+        {
+            return poolSize < Integer.MAX_VALUE
+                ? Executors.newFixedThreadPool( poolSize )
+                : Executors.newCachedThreadPool();
         }
 
-        private Scheduler createMaster(ExecutorService pool, int poolSize) {
-            if (!areSuitesAndClassesParallel() || poolSize <= 1) {
-                return new Scheduler(null, new InvokerStrategy());
-            } else if (pool != null && poolSize == Integer.MAX_VALUE) {
-                return new Scheduler(null, new SharedThreadPoolStrategy(pool));
-            } else {
-                return new Scheduler(null, SchedulingStrategies.createParallelStrategy(2));
+        private Scheduler createMaster( ExecutorService pool, int poolSize )
+        {
+            if ( !areSuitesAndClassesParallel() || poolSize <= 1 )
+            {
+                return new Scheduler( null, new InvokerStrategy() );
+            }
+            else if ( pool != null && poolSize == Integer.MAX_VALUE )
+            {
+                return new Scheduler( null, new SharedThreadPoolStrategy( pool ) );
+            }
+            else
+            {
+                return new Scheduler( null, SchedulingStrategies.createParallelStrategy( 2 ) );
             }
         }
 
-        private boolean areSuitesAndClassesParallel() {
-            return !suites.isEmpty() && allGroups.get(Type.SUITES) > 0 && !classes.isEmpty() && allGroups.get(Type.CLASSES) > 0;
+        private boolean areSuitesAndClassesParallel()
+        {
+            return !suites.isEmpty() && allGroups.get( Type.SUITES ) > 0 && !classes.isEmpty()
+                && allGroups.get( Type.CLASSES ) > 0;
         }
 
-        private void populateChildrenFromSuites() {
+        private void populateChildrenFromSuites()
+        {
             Filter filter = new SuiteFilter();
-            for (Iterator<ParentRunner> it = suites.iterator(); it.hasNext();) {
+            for ( Iterator<ParentRunner> it = suites.iterator(); it.hasNext(); )
+            {
                 ParentRunner suite = it.next();
-                try {
-                    suite.filter(filter);
-                } catch (NoTestsRemainException e) {
+                try
+                {
+                    suite.filter( filter );
+                }
+                catch ( NoTestsRemainException e )
+                {
                     it.remove();
                 }
             }
         }
 
-        private int totalPoolSize() {
-            if (poolCapacity == TOTAL_POOL_SIZE_UNDEFINED) {
+        private int totalPoolSize()
+        {
+            if ( poolCapacity == TOTAL_POOL_SIZE_UNDEFINED )
+            {
                 int total = 0;
-                for (int nThreads : allGroups.values()) {
+                for ( int nThreads : allGroups.values() )
+                {
                     total += nThreads;
-                    if (total < 0) {
+                    if ( total < 0 )
+                    {
                         total = Integer.MAX_VALUE;
                         break;
                     }
                 }
                 return total;
-            } else {
+            }
+            else
+            {
                 return poolCapacity;
             }
         }
 
-        private Runner setSchedulers() throws InitializationError {
-            int parallelSuites = allGroups.get(Type.SUITES);
-            int parallelClasses = allGroups.get(Type.CLASSES);
-            int parallelMethods = allGroups.get(Type.METHODS);
+        private Runner setSchedulers()
+            throws InitializationError
+        {
+            int parallelSuites = allGroups.get( Type.SUITES );
+            int parallelClasses = allGroups.get( Type.CLASSES );
+            int parallelMethods = allGroups.get( Type.METHODS );
             int poolSize = totalPoolSize();
-            ExecutorService commonPool = splitPool || poolSize == 0 ? null : createPool(poolSize);
-            master = createMaster(commonPool, poolSize);
+            ExecutorService commonPool = splitPool || poolSize == 0 ? null : createPool( poolSize );
+            master = createMaster( commonPool, poolSize );
 
             ParentRunner suiteSuites = wrapRunners( suites );
             if ( suiteSuites != null )
@@ -343,7 +396,8 @@ public class ParallelComputerBuilder {
             return all;
         }
 
-        private ParentRunner createFinalRunner( Runner... runners ) throws InitializationError
+        private ParentRunner createFinalRunner( Runner... runners )
+            throws InitializationError
         {
             ArrayList<Runner> all = new ArrayList<Runner>( unscheduledRunners );
             for ( Runner runner : runners )
@@ -361,6 +415,7 @@ public class ParallelComputerBuilder {
                 {
                     try
                     {
+                        beforeRunQuietly();
                         super.run( notifier );
                     }
                     finally
@@ -371,46 +426,96 @@ public class ParallelComputerBuilder {
             };
         }
 
-        private void setSchedulers(Iterable<? extends ParentRunner> runners, int poolSize, ExecutorService commonPool) {
-            if (commonPool != null) {
-                Balancer concurrencyLimit = BalancerFactory.createBalancerWithFairness(poolSize);
+        private void setSchedulers( Iterable<? extends ParentRunner> runners, int poolSize, ExecutorService commonPool )
+        {
+            if ( commonPool != null )
+            {
+                Balancer concurrencyLimit = BalancerFactory.createBalancerWithFairness( poolSize );
                 boolean doParallel = poolSize > 0;
-                for (ParentRunner runner : runners) {
-                    runner.setScheduler(createScheduler(runner.getDescription(), commonPool, doParallel, concurrencyLimit));
+                for ( ParentRunner runner : runners )
+                {
+                    runner.setScheduler(
+                        createScheduler( runner.getDescription(), commonPool, doParallel, concurrencyLimit ) );
                 }
-            } else {
+            }
+            else
+            {
                 ExecutorService pool = null;
-                if (poolSize == Integer.MAX_VALUE) {
+                if ( poolSize == Integer.MAX_VALUE )
+                {
                     pool = Executors.newCachedThreadPool();
-                } else if (poolSize > 0) {
-                    pool = Executors.newFixedThreadPool(poolSize);
+                }
+                else if ( poolSize > 0 )
+                {
+                    pool = Executors.newFixedThreadPool( poolSize );
                 }
                 boolean doParallel = pool != null;
-                for (ParentRunner runner : runners) {
-                    runner.setScheduler(createScheduler(runner.getDescription(), pool, doParallel,
-                            BalancerFactory.createInfinitePermitsBalancer()));
+                for ( ParentRunner runner : runners )
+                {
+                    runner.setScheduler( createScheduler( runner.getDescription(), pool, doParallel,
+                                                          BalancerFactory.createInfinitePermitsBalancer() ) );
                 }
             }
         }
 
-        private Scheduler createScheduler(Description desc, ExecutorService pool, boolean doParallel, Balancer concurrency) {
+        private Scheduler createScheduler( Description desc, ExecutorService pool, boolean doParallel,
+                                           Balancer concurrency )
+        {
             doParallel &= pool != null;
-            SchedulingStrategy strategy = doParallel ? new SharedThreadPoolStrategy(pool) : new InvokerStrategy();
-            return new Scheduler(desc, master, strategy, concurrency);
+            SchedulingStrategy strategy = doParallel ? new SharedThreadPoolStrategy( pool ) : new InvokerStrategy();
+            return new Scheduler( desc, master, strategy, concurrency );
         }
 
-        private Scheduler createScheduler(int poolSize) {
-            if (poolSize == Integer.MAX_VALUE) {
-                return new Scheduler(null, master, SchedulingStrategies.createParallelStrategyUnbounded());
-            } else if (poolSize == 0) {
-                return new Scheduler(null, master, new InvokerStrategy());
-            } else {
-                return new Scheduler(null, master, SchedulingStrategies.createParallelStrategy(poolSize));
+        private Scheduler createScheduler( int poolSize )
+        {
+            if ( poolSize == Integer.MAX_VALUE )
+            {
+                return new Scheduler( null, master, SchedulingStrategies.createParallelStrategyUnbounded() );
+            }
+            else if ( poolSize == 0 )
+            {
+                return new Scheduler( null, master, new InvokerStrategy() );
+            }
+            else
+            {
+                return new Scheduler( null, master, SchedulingStrategies.createParallelStrategy( poolSize ) );
             }
         }
 
-        private boolean canSchedule(Runner runner) {
-            return !(runner instanceof ErrorReportingRunner) && runner instanceof ParentRunner;
+        private boolean canSchedule( Runner runner )
+        {
+            return !( runner instanceof ErrorReportingRunner ) && runner instanceof ParentRunner;
+        }
+
+        private class SuiteFilter
+            extends Filter
+        {
+            @Override
+            public boolean shouldRun( Description description )
+            {
+                return true;
+            }
+
+            @Override
+            public void apply( Object child )
+                throws NoTestsRemainException
+            {
+                super.apply( child );
+                if ( child instanceof Suite )
+                {
+                    nestedSuites.add( (Suite) child );
+                }
+                else if ( child instanceof ParentRunner )
+                {
+                    nestedClasses.add( (ParentRunner) child );
+                }
+            }
+
+            @Override
+            public String describe()
+            {
+                return "";
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Scheduler.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Scheduler.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Scheduler.java
index 7b287e5..d3c4133 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Scheduler.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/Scheduler.java
@@ -31,87 +31,100 @@ import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadPoolExecutor;
 
 /**
- *
  * Schedules tests, controls thread resources, awaiting tests and other schedulers finished, and
  * a master scheduler can shutdown slaves.
- * <p>
+ * <p/>
  * The scheduler objects should be first created (and wired) and set in runners
  * {@link org.junit.runners.ParentRunner#setScheduler(org.junit.runners.model.RunnerScheduler)}.
- * <p>
+ * <p/>
  * A new instance of scheduling strategy should be passed to the constructor of this scheduler.
  *
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public class Scheduler implements RunnerScheduler {
+public class Scheduler
+    implements RunnerScheduler
+{
     private final Balancer balancer;
+
     private final SchedulingStrategy strategy;
+
     private final Set<Controller> slaves = new CopyOnWriteArraySet<Controller>();
+
     private final Description description;
+
     private volatile boolean shutdown = false;
+
     private volatile boolean started = false;
+
     private volatile Controller masterController;
 
     /**
      * Use e.g. parallel classes have own non-shared thread pool, and methods another pool.
-     * <p>
+     * <p/>
      * You can use it with one infinite thread pool shared in strategies across all
      * suites, class runners, etc.
      */
-    public Scheduler(Description description, SchedulingStrategy strategy) {
-        this(description, strategy, -1);
+    public Scheduler( Description description, SchedulingStrategy strategy )
+    {
+        this( description, strategy, -1 );
     }
 
     /**
      * Should be used if schedulers in parallel children and parent use one instance of bounded thread pool.
-     * <p>
+     * <p/>
      * Set this scheduler in a e.g. one suite of classes, then every individual class runner should reference
      * {@link #Scheduler(org.junit.runner.Description, Scheduler, SchedulingStrategy)}
      * or {@link #Scheduler(org.junit.runner.Description, Scheduler, SchedulingStrategy, int)}.
      *
      * @param description description of current runner
-     * @param strategy scheduling strategy with a shared thread pool
+     * @param strategy    scheduling strategy with a shared thread pool
      * @param concurrency determines maximum concurrent children scheduled a time via {@link #schedule(Runnable)}
      * @throws NullPointerException if null <tt>strategy</tt>
      */
-    public Scheduler(Description description, SchedulingStrategy strategy, int concurrency) {
-        this(description, strategy, BalancerFactory.createBalancer(concurrency));
+    public Scheduler( Description description, SchedulingStrategy strategy, int concurrency )
+    {
+        this( description, strategy, BalancerFactory.createBalancer( concurrency ) );
     }
 
     /**
      * New instances should be used by schedulers with limited concurrency by <tt>balancer</tt>
      * against other groups of schedulers. The schedulers share one pool.
-     * <p>
+     * <p/>
      * Unlike in {@link #Scheduler(org.junit.runner.Description, SchedulingStrategy, int)} which was limiting
      * the <tt>concurrency</tt> of children of a runner where this scheduler was set, <em>this</em> <tt>balancer</tt>
      * is limiting the concurrency of all children in runners having schedulers created by this constructor.
      *
      * @param description description of current runner
-     * @param strategy scheduling strategy which may share threads with other strategy
-     * @param balancer determines maximum concurrent children scheduled a time via {@link #schedule(Runnable)}
+     * @param strategy    scheduling strategy which may share threads with other strategy
+     * @param balancer    determines maximum concurrent children scheduled a time via {@link #schedule(Runnable)}
      * @throws NullPointerException if null <tt>strategy</tt> or <tt>balancer</tt>
      */
-    public Scheduler(Description description, SchedulingStrategy strategy, Balancer balancer) {
-        strategy.setDefaultShutdownHandler(newShutdownHandler());
+    public Scheduler( Description description, SchedulingStrategy strategy, Balancer balancer )
+    {
+        strategy.setDefaultShutdownHandler( newShutdownHandler() );
         this.description = description;
         this.strategy = strategy;
         this.balancer = balancer;
         masterController = null;
     }
+
     /**
      * Can be used by e.g. a runner having parallel classes in use case with parallel
      * suites, classes and methods sharing the same thread pool.
      *
-     * @param description description of current runner
+     * @param description     description of current runner
      * @param masterScheduler scheduler sharing own threads with this slave
-     * @param strategy scheduling strategy for this scheduler
-     * @param balancer determines maximum concurrent children scheduled a time via {@link #schedule(Runnable)}
+     * @param strategy        scheduling strategy for this scheduler
+     * @param balancer        determines maximum concurrent children scheduled a time via {@link #schedule(Runnable)}
      * @throws NullPointerException if null <tt>masterScheduler</tt>, <tt>strategy</tt> or <tt>balancer</tt>
      */
-    public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy, Balancer balancer) {
-        this(description, strategy, balancer);
-        strategy.setDefaultShutdownHandler(newShutdownHandler());
-        masterScheduler.register(this);
+    public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy,
+                      Balancer balancer )
+    {
+        this( description, strategy, balancer );
+        strategy.setDefaultShutdownHandler( newShutdownHandler() );
+        masterScheduler.register( this );
     }
 
     /**
@@ -120,25 +133,29 @@ public class Scheduler implements RunnerScheduler {
      * @see #Scheduler(org.junit.runner.Description, SchedulingStrategy)
      * @see #Scheduler(org.junit.runner.Description, SchedulingStrategy, int)
      */
-    public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy, int concurrency) {
-        this(description, strategy, concurrency);
-        strategy.setDefaultShutdownHandler(newShutdownHandler());
-        masterScheduler.register(this);
+    public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy, int concurrency )
+    {
+        this( description, strategy, concurrency );
+        strategy.setDefaultShutdownHandler( newShutdownHandler() );
+        masterScheduler.register( this );
     }
 
     /**
      * Should be used with individual pools on suites, classes and methods, see
      * {@link org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder#useSeparatePools()}.
-     * <p>
+     * <p/>
      * Cached thread pool is infinite and can be always shared.
      */
-    public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy) {
-        this(description, masterScheduler, strategy, 0);
+    public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy )
+    {
+        this( description, masterScheduler, strategy, 0 );
     }
 
-    private void setController(Controller masterController) {
-        if (masterController == null) {
-            throw new NullPointerException("null ExecutionController");
+    private void setController( Controller masterController )
+    {
+        if ( masterController == null )
+        {
+            throw new NullPointerException( "null ExecutionController" );
         }
         this.masterController = masterController;
     }
@@ -147,14 +164,17 @@ public class Scheduler implements RunnerScheduler {
      * @param slave a slave scheduler to register
      * @return <tt>true</tt> if successfully registered the <tt>slave</tt>.
      */
-    private boolean register(Scheduler slave) {
+    private boolean register( Scheduler slave )
+    {
         boolean canRegister = slave != null && slave != this;
-        if (canRegister) {
-            Controller controller = new Controller(slave);
-            canRegister = !slaves.contains(controller);
-            if (canRegister) {
-                slaves.add(controller);
-                slave.setController(controller);
+        if ( canRegister )
+        {
+            Controller controller = new Controller( slave );
+            canRegister = !slaves.contains( controller );
+            if ( canRegister )
+            {
+                slaves.add( controller );
+                slave.setController( controller );
             }
         }
         return canRegister;
@@ -163,50 +183,65 @@ public class Scheduler implements RunnerScheduler {
     /**
      * @return <tt>true</tt> if new tasks can be scheduled.
      */
-    private boolean canSchedule() {
-        return !shutdown && (masterController == null || masterController.canSchedule());
+    private boolean canSchedule()
+    {
+        return !shutdown && ( masterController == null || masterController.canSchedule() );
     }
 
-    protected void logQuietly(Throwable t) {
-        t.printStackTrace(System.err);
+    protected void logQuietly( Throwable t )
+    {
+        t.printStackTrace( System.err );
     }
 
-    protected void logQuietly(String msg) {
-        System.err.println(msg);
+    protected void logQuietly( String msg )
+    {
+        System.err.println( msg );
     }
 
     /**
      * Attempts to stop all actively executing tasks and immediately returns a collection
      * of descriptions of those tasks which have started prior to this call.
-     * <p>
+     * <p/>
      * This scheduler and other registered schedulers will shutdown, see {@link #register(Scheduler)}.
      * If <tt>shutdownNow</tt> is set, waiting methods will be interrupted via {@link Thread#interrupt}.
      *
      * @param shutdownNow if <tt>true</tt> interrupts waiting methods
      * @return collection of descriptions started before shutting down
      */
-    public Collection<Description> shutdown(boolean shutdownNow) {
+    public Collection<Description> shutdown( boolean shutdownNow )
+    {
         shutdown = true;
         ArrayList<Description> activeChildren = new ArrayList<Description>();
 
-        if (started && description != null) {
-            activeChildren.add(description);
+        if ( started && description != null )
+        {
+            activeChildren.add( description );
         }
 
-        for (Controller slave : slaves) {
-            try {
-                activeChildren.addAll(slave.shutdown(shutdownNow));
-            } catch (Throwable t) {
-                logQuietly(t);
+        for ( Controller slave : slaves )
+        {
+            try
+            {
+                activeChildren.addAll( slave.shutdown( shutdownNow ) );
+            }
+            catch ( Throwable t )
+            {
+                logQuietly( t );
             }
         }
 
-        try {
+        try
+        {
             balancer.releaseAllPermits();
-        } finally {
-            if (shutdownNow) {
+        }
+        finally
+        {
+            if ( shutdownNow )
+            {
                 strategy.stopNow();
-            } else {
+            }
+            else
+            {
                 strategy.stop();
             }
         }
@@ -214,52 +249,82 @@ public class Scheduler implements RunnerScheduler {
         return activeChildren;
     }
 
-    protected void beforeExecute() {
+    protected void beforeExecute()
+    {
     }
 
-    protected void afterExecute() {
+    protected void afterExecute()
+    {
     }
 
-    public void schedule(Runnable childStatement) {
-        if (childStatement == null) {
-            logQuietly("cannot schedule null");
-        } else if (canSchedule() && strategy.canSchedule()) {
-            try {
-                balancer.acquirePermit();
-                Runnable task = wrapTask(childStatement);
-                strategy.schedule(task);
-                started = true;
-            } catch (RejectedExecutionException e) {
-                shutdown(false);
-            } catch (Throwable t) {
+    public void schedule( Runnable childStatement )
+    {
+        if ( childStatement == null )
+        {
+            logQuietly( "cannot schedule null" );
+        }
+        else if ( canSchedule() && strategy.canSchedule() )
+        {
+            try
+            {
+                boolean isNotInterrupted = balancer.acquirePermit();
+                if ( isNotInterrupted && !shutdown )
+                {
+                    Runnable task = wrapTask( childStatement );
+                    strategy.schedule( task );
+                    started = true;
+                }
+            }
+            catch ( RejectedExecutionException e )
+            {
+                shutdown( false );
+            }
+            catch ( Throwable t )
+            {
                 balancer.releasePermit();
-                logQuietly(t);
+                logQuietly( t );
             }
         }
     }
 
-    public void finished() {
-        try {
+    public void finished()
+    {
+        try
+        {
             strategy.finished();
-        } catch (InterruptedException e) {
-            logQuietly(e);
-        } finally {
-            for (Controller slave : slaves) {
+        }
+        catch ( InterruptedException e )
+        {
+            logQuietly( e );
+        }
+        finally
+        {
+            for ( Controller slave : slaves )
+            {
                 slave.awaitFinishedQuietly();
             }
         }
     }
 
-    private Runnable wrapTask(final Runnable task) {
-        return new Runnable() {
-            public void run() {
-                try {
+    private Runnable wrapTask( final Runnable task )
+    {
+        return new Runnable()
+        {
+            public void run()
+            {
+                try
+                {
                     beforeExecute();
                     task.run();
-                } finally {
-                    try {
+                }
+                finally
+                {
+                    try
+                    {
                         afterExecute();
-                    } finally {
+                    }
+                    finally
+                    {
                         balancer.releasePermit();
                     }
                 }
@@ -267,68 +332,86 @@ public class Scheduler implements RunnerScheduler {
         };
     }
 
-    protected ShutdownHandler newShutdownHandler() {
+    protected ShutdownHandler newShutdownHandler()
+    {
         return new ShutdownHandler();
     }
 
     /**
      * If this is a master scheduler, the slaves can stop scheduling by the master through the controller.
      */
-    private final class Controller {
+    private final class Controller
+    {
         private final Scheduler slave;
 
-        private Controller(Scheduler slave) {
+        private Controller( Scheduler slave )
+        {
             this.slave = slave;
         }
 
         /**
          * @return <tt>true</tt> if new children can be scheduled.
          */
-        boolean canSchedule() {
+        boolean canSchedule()
+        {
             return Scheduler.this.canSchedule();
         }
 
-        void awaitFinishedQuietly() {
-            try {
+        void awaitFinishedQuietly()
+        {
+            try
+            {
                 slave.finished();
-            } catch(Throwable t) {
-                slave.logQuietly(t);
+            }
+            catch ( Throwable t )
+            {
+                slave.logQuietly( t );
             }
         }
 
-        Collection<Description> shutdown(boolean shutdownNow) {
-            return slave.shutdown(shutdownNow);
+        Collection<Description> shutdown( boolean shutdownNow )
+        {
+            return slave.shutdown( shutdownNow );
         }
 
         @Override
-        public int hashCode() {
+        public int hashCode()
+        {
             return slave.hashCode();
         }
 
         @Override
-        public boolean equals(Object o) {
-            return o == this || (o instanceof Controller) && slave.equals(((Controller) o).slave);
+        public boolean equals( Object o )
+        {
+            return o == this || ( o instanceof Controller ) && slave.equals( ( (Controller) o ).slave );
         }
     }
 
-    public class ShutdownHandler implements RejectedExecutionHandler {
+    public class ShutdownHandler
+        implements RejectedExecutionHandler
+    {
         private volatile RejectedExecutionHandler poolHandler;
 
-        protected ShutdownHandler() {
+        protected ShutdownHandler()
+        {
             poolHandler = null;
         }
 
-        public void setRejectedExecutionHandler(RejectedExecutionHandler poolHandler) {
+        public void setRejectedExecutionHandler( RejectedExecutionHandler poolHandler )
+        {
             this.poolHandler = poolHandler;
         }
 
-        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
-            if (executor.isShutdown()) {
-                shutdown(false);
+        public void rejectedExecution( Runnable r, ThreadPoolExecutor executor )
+        {
+            if ( executor.isShutdown() )
+            {
+                shutdown( false );
             }
             final RejectedExecutionHandler poolHandler = this.poolHandler;
-            if (poolHandler != null) {
-                poolHandler.rejectedExecution(r, executor);
+            if ( poolHandler != null )
+            {
+                poolHandler.rejectedExecution( r, executor );
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategies.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategies.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategies.java
index 4d3c6a6..475f4c0 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategies.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategies.java
@@ -28,12 +28,14 @@ import java.util.concurrent.Executors;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public class SchedulingStrategies {
+public class SchedulingStrategies
+{
 
     /**
      * @return sequentially executing strategy
      */
-    public static SchedulingStrategy createInvokerStrategy() {
+    public static SchedulingStrategy createInvokerStrategy()
+    {
         return new InvokerStrategy();
     }
 
@@ -41,20 +43,22 @@ public class SchedulingStrategies {
      * @param nThreads fixed pool capacity
      * @return parallel scheduling strategy
      */
-    public static SchedulingStrategy createParallelStrategy(int nThreads) {
-        return new NonSharedThreadPoolStrategy(Executors.newFixedThreadPool(nThreads));
+    public static SchedulingStrategy createParallelStrategy( int nThreads )
+    {
+        return new NonSharedThreadPoolStrategy( Executors.newFixedThreadPool( nThreads ) );
     }
 
     /**
      * @return parallel scheduling strategy with unbounded capacity
      */
-    public static SchedulingStrategy createParallelStrategyUnbounded() {
-        return new NonSharedThreadPoolStrategy(Executors.newCachedThreadPool());
+    public static SchedulingStrategy createParallelStrategyUnbounded()
+    {
+        return new NonSharedThreadPoolStrategy( Executors.newCachedThreadPool() );
     }
 
     /**
      * The <tt>threadPool</tt> passed to this strategy can be shared in other strategies.
-     * <p>
+     * <p/>
      * The call {@link SchedulingStrategy#finished()} is waiting until own tasks have finished.
      * New tasks will not be scheduled by this call in this strategy. This strategy is not
      * waiting for other strategies to finish. The {@link org.junit.runners.model.RunnerScheduler#finished()} may
@@ -64,10 +68,12 @@ public class SchedulingStrategies {
      * @return parallel strategy with shared thread pool
      * @throws NullPointerException if <tt>threadPool</tt> is null
      */
-    public static SchedulingStrategy createParallelSharedStrategy(ExecutorService threadPool) {
-        if (threadPool == null) {
-            throw new NullPointerException("null threadPool in #createParallelSharedStrategy");
+    public static SchedulingStrategy createParallelSharedStrategy( ExecutorService threadPool )
+    {
+        if ( threadPool == null )
+        {
+            throw new NullPointerException( "null threadPool in #createParallelSharedStrategy" );
         }
-        return new SharedThreadPoolStrategy(threadPool);
+        return new SharedThreadPoolStrategy( threadPool );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategy.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategy.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategy.java
index c9da764..f419cb7 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategy.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SchedulingStrategy.java
@@ -35,19 +35,20 @@ import java.util.concurrent.RejectedExecutionException;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-public abstract class SchedulingStrategy {
+public abstract class SchedulingStrategy
+{
 
     /**
      * Schedules tasks if {@link #canSchedule()}.
      *
      * @param task runnable to schedule in a thread pool or invoke
      * @throws RejectedExecutionException if <tt>task</tt>
-     *         cannot be scheduled for execution
-     * @throws NullPointerException if <tt>task</tt> is <tt>null</tt>
+     *                                    cannot be scheduled for execution
+     * @throws NullPointerException       if <tt>task</tt> is <tt>null</tt>
      * @see RunnerScheduler#schedule(Runnable)
      * @see java.util.concurrent.Executor#execute(Runnable)
      */
-    protected abstract void schedule(Runnable task);
+    protected abstract void schedule( Runnable task );
 
     /**
      * Waiting for scheduled tasks to finish.
@@ -57,10 +58,11 @@ public abstract class SchedulingStrategy {
      *         <tt>false</tt> if already stopped (a <em>shared</em> thread
      *         pool was shutdown externally).
      * @throws InterruptedException if interrupted while waiting
-     *         for scheduled tasks to finish
+     *                              for scheduled tasks to finish
      * @see RunnerScheduler#finished()
      */
-    protected abstract boolean finished() throws InterruptedException;
+    protected abstract boolean finished()
+        throws InterruptedException;
 
     /**
      * Stops scheduling new tasks (e.g. by {@link java.util.concurrent.ExecutorService#shutdown()}
@@ -77,7 +79,7 @@ public abstract class SchedulingStrategy {
      * Stops scheduling new tasks and <em>interrupts</em> running tasks
      * (e.g. by {@link java.util.concurrent.ExecutorService#shutdownNow()} on a private thread pool
      * which cannot be <em>shared</em> with other strategy).
-     * <p>
+     * <p/>
      * This method calls {@link #stop()} by default.
      *
      * @return <tt>true</tt> if successfully stopped the scheduler, else
@@ -85,16 +87,18 @@ public abstract class SchedulingStrategy {
      *         pool was shutdown externally).
      * @see java.util.concurrent.ExecutorService#shutdownNow()
      */
-    protected boolean stopNow() {
+    protected boolean stopNow()
+    {
         return stop();
     }
 
-    protected void setDefaultShutdownHandler(Scheduler.ShutdownHandler handler) {
+    protected void setDefaultShutdownHandler( Scheduler.ShutdownHandler handler )
+    {
     }
 
     /**
      * @return <tt>true</tt> if a thread pool associated with this strategy
-     * can be shared with other strategies.
+     *         can be shared with other strategies.
      */
     protected abstract boolean hasSharedThreadPool();
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SharedThreadPoolStrategy.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SharedThreadPoolStrategy.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SharedThreadPoolStrategy.java
index 53082c4..88907e6 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SharedThreadPoolStrategy.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/SharedThreadPoolStrategy.java
@@ -29,33 +29,46 @@ import java.util.concurrent.Future;
  * Parallel strategy for shared thread pool in private package.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see AbstractThreadPoolStrategy
+ * @since 2.16
  */
-final class SharedThreadPoolStrategy extends AbstractThreadPoolStrategy {
-    SharedThreadPoolStrategy(ExecutorService threadPool) {
-        super(threadPool, new ConcurrentLinkedQueue<Future<?>>());
+final class SharedThreadPoolStrategy
+    extends AbstractThreadPoolStrategy
+{
+    SharedThreadPoolStrategy( ExecutorService threadPool )
+    {
+        super( threadPool, new ConcurrentLinkedQueue<Future<?>>() );
     }
 
     @Override
-    public boolean hasSharedThreadPool() {
+    public boolean hasSharedThreadPool()
+    {
         return true;
     }
 
     @Override
-    public boolean finished() throws InterruptedException {
+    public boolean finished()
+        throws InterruptedException
+    {
         boolean wasRunningAll = canSchedule();
-        for (Future<?> futureResult : getFutureResults()) {
-            try {
+        for ( Future<?> futureResult : getFutureResults() )
+        {
+            try
+            {
                 futureResult.get();
-            } catch (InterruptedException e) {
+            }
+            catch ( InterruptedException e )
+            {
                 // after called external ExecutorService#shutdownNow()
                 // or ExecutorService#shutdown()
                 wasRunningAll = false;
-            } catch (ExecutionException e) {
+            }
+            catch ( ExecutionException e )
+            {
                 // test throws exception
-            } catch (CancellationException e) {
+            }
+            catch ( CancellationException e )
+            {
                 // cannot happen because not calling Future#cancel()
             }
         }
@@ -64,19 +77,23 @@ final class SharedThreadPoolStrategy extends AbstractThreadPoolStrategy {
     }
 
     @Override
-    protected final boolean stop() {
-        return stop(false);
+    protected final boolean stop()
+    {
+        return stop( false );
     }
 
     @Override
-    protected final boolean stopNow() {
-        return stop(true);
+    protected final boolean stopNow()
+    {
+        return stop( true );
     }
 
-    private boolean stop(boolean interrupt) {
+    private boolean stop( boolean interrupt )
+    {
         final boolean wasRunning = canSchedule();
-        for (Future<?> futureResult : getFutureResults()) {
-            futureResult.cancel(interrupt);
+        for ( Future<?> futureResult : getFutureResults() )
+        {
+            futureResult.cancel( interrupt );
         }
         disable();
         return wasRunning;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ThreadResourcesBalancer.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ThreadResourcesBalancer.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ThreadResourcesBalancer.java
index 80d116d..322d443 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ThreadResourcesBalancer.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/ThreadResourcesBalancer.java
@@ -23,13 +23,14 @@ import java.util.concurrent.Semaphore;
 
 /**
  * @author Tibor Digana (tibor17)
- * @since 2.16
- *
  * @see Balancer
+ * @since 2.16
  */
-final class ThreadResourcesBalancer implements Balancer
+final class ThreadResourcesBalancer
+    implements Balancer
 {
     private final Semaphore balancer;
+
     private final int numPermits;
 
     /**
@@ -37,7 +38,6 @@ final class ThreadResourcesBalancer implements Balancer
      *
      * @param numPermits number of permits to acquire when maintaining concurrency on tests.
      *                   Must be &gt;0 and &lt; {@link Integer#MAX_VALUE}.
-     *
      * @see #ThreadResourcesBalancer(int, boolean)
      */
     ThreadResourcesBalancer( int numPermits )
@@ -48,7 +48,7 @@ final class ThreadResourcesBalancer implements Balancer
     /**
      * @param numPermits number of permits to acquire when maintaining concurrency on tests.
      *                   Must be &gt;0 and &lt; {@link Integer#MAX_VALUE}.
-     * @param fair <tt>true</tt> guarantees the waiting schedulers to wake up in order they acquired a permit
+     * @param fair       <tt>true</tt> guarantees the waiting schedulers to wake up in order they acquired a permit
      */
     ThreadResourcesBalancer( int numPermits, boolean fair )
     {


[3/3] git commit: reformat code + IT + junit.apt.vm + fork-options-and-parllel-execution.apt.vm

Posted by ag...@apache.org.
reformat code + IT + junit.apt.vm + fork-options-and-parllel-execution.apt.vm


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

Branch: refs/heads/master
Commit: a9d511a037f07bf9d40b908ca927b646eb96fb47
Parents: 911d374
Author: Tibor Digana <ti...@lycos.com>
Authored: Thu Aug 15 07:20:41 2013 +0200
Committer: Andreas Gudian <ag...@apache.org>
Committed: Fri Aug 16 10:34:38 2013 +0200

----------------------------------------------------------------------
 .../plugin/failsafe/IntegrationTestMojo.java    |  18 +-
 .../plugin/surefire/AbstractSurefireMojo.java   |   6 +-
 .../surefire/SurefireExecutionParameters.java   |   8 +-
 .../booterclient/ChecksumCalculator.java        |   5 +
 .../maven/plugin/surefire/SurefirePlugin.java   |  18 +-
 .../fork-options-and-parallel-execution.apt.vm  |  51 +-
 .../src/site/apt/examples/junit.apt.vm          |   4 +
 .../maven/surefire/its/JUnit47ParallelIT.java   | 495 +++++++++++++++++++
 .../surefire/its/fixture/MavenLauncher.java     |   5 +
 .../surefire/its/fixture/SurefireLauncher.java  |  68 ++-
 .../src/test/resources/junit47-parallel/pom.xml |  33 ++
 .../test/java/surefireparallel/Suite1Test.java  |  39 ++
 .../test/java/surefireparallel/Suite2Test.java  |  39 ++
 .../test/java/surefireparallel/TestClass.java   |  53 ++
 .../java/surefireparallel/Waiting1Test.java     |  50 ++
 .../java/surefireparallel/Waiting2Test.java     |  50 ++
 .../java/surefireparallel/Waiting3Test.java     |  50 ++
 .../java/surefireparallel/Waiting4Test.java     |  50 ++
 .../java/surefireparallel/Waiting5Test.java     |  50 ++
 .../java/surefireparallel/Waiting6Test.java     |  50 ++
 .../java/surefireparallel/Waiting7Test.java     |  50 ++
 .../java/surefireparallel/Waiting8Test.java     |  50 ++
 .../surefire/junitcore/JUnitCoreParameters.java |  57 ++-
 .../surefire/junitcore/JUnitCoreWrapper.java    | 167 ++-----
 .../junitcore/NonConcurrentRunListener.java     |   6 +-
 .../junitcore/ParallelComputerFactory.java      | 107 ++--
 .../pc/AbstractThreadPoolStrategy.java          |  80 +--
 .../maven/surefire/junitcore/pc/Balancer.java   |   5 +-
 .../surefire/junitcore/pc/BalancerFactory.java  |   6 +-
 .../surefire/junitcore/pc/InvokerStrategy.java  |  30 +-
 .../pc/NonSharedThreadPoolStrategy.java         |  28 +-
 .../surefire/junitcore/pc/NullBalancer.java     |   6 +-
 .../surefire/junitcore/pc/ParallelComputer.java | 117 ++++-
 .../junitcore/pc/ParallelComputerBuilder.java   | 357 ++++++++-----
 .../maven/surefire/junitcore/pc/Scheduler.java  | 299 +++++++----
 .../junitcore/pc/SchedulingStrategies.java      |  28 +-
 .../junitcore/pc/SchedulingStrategy.java        |  24 +-
 .../junitcore/pc/SharedThreadPoolStrategy.java  |  55 ++-
 .../junitcore/pc/ThreadResourcesBalancer.java   |  10 +-
 .../junitcore/ParallelComputerFactoryTest.java  | 256 ++++++++--
 .../maven/surefire/junitcore/Stopwatch.java     |  46 ++
 .../pc/ParallelComputerBuilderTest.java         | 470 ++++++++++--------
 .../surefire/junitcore/pc/RangeMatcher.java     |  12 +-
 .../junitcore/pc/SchedulingStrategiesTest.java  | 140 +++---
 .../maven/surefire/junitcore/pc/Stopwatch.java  |  45 --
 45 files changed, 2648 insertions(+), 945 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
index 41278c3..3329bcb 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
@@ -140,24 +140,30 @@ public class IntegrationTestMojo
 
     /**
      * Stop executing queued parallel JUnit tests after a certain number of seconds.
+     * <br/>
+     * Example values: "3.5", "4"<br/>
+     * <br/>
      * If set to 0, wait forever, never timing out.
      * Makes sense with specified <code>parallel</code> different from "none".
      *
      * @since 2.16
      */
     @Parameter( property = "failsafe.parallel.timeout" )
-    private int parallelTestsTimeoutInSeconds;
+    private double parallelTestsTimeoutInSeconds;
 
     /**
      * Stop executing queued parallel JUnit tests
      * and <em>interrupt</em> currently running tests after a certain number of seconds.
+     * <br/>
+     * Example values: "3.5", "4"<br/>
+     * <br/>
      * If set to 0, wait forever, never timing out.
      * Makes sense with specified <code>parallel</code> different from "none".
      *
      * @since 2.16
      */
     @Parameter( property = "failsafe.parallel.forcedTimeout" )
-    private int parallelTestsTimeoutForcedInSeconds;
+    private double parallelTestsTimeoutForcedInSeconds;
     
     /**
      * A list of &lt;include> elements specifying the tests (by pattern) that should be included in testing. When not
@@ -454,19 +460,19 @@ public class IntegrationTestMojo
         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
     }
 
-    public int getParallelTestsTimeoutInSeconds() {
+    public double getParallelTestsTimeoutInSeconds() {
         return parallelTestsTimeoutInSeconds;
     }
 
-    public void setParallelTestsTimeoutInSeconds( int parallelTestsTimeoutInSeconds ) {
+    public void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds ) {
         this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
     }
 
-    public int getParallelTestsTimeoutForcedInSeconds() {
+    public double getParallelTestsTimeoutForcedInSeconds() {
         return parallelTestsTimeoutForcedInSeconds;
     }
 
-    public void setParallelTestsTimeoutForcedInSeconds( int parallelTestsTimeoutForcedInSeconds ) {
+    public void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds ) {
         this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 5975d7d..d8b9f9d 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -1143,9 +1143,9 @@ public abstract class AbstractSurefireMojo
         getProperties().setProperty( ProviderParameterNames.THREADCOUNTCLASSES_PROP, Integer.toString( getThreadCountClasses() ) );
         getProperties().setProperty( ProviderParameterNames.THREADCOUNTMETHODS_PROP, Integer.toString( getThreadCountMethods() ) );
         getProperties().setProperty( ProviderParameterNames.PARALLEL_TIMEOUT_PROP,
-                Integer.toString( getParallelTestsTimeoutInSeconds() ) );
+                Double.toString( getParallelTestsTimeoutInSeconds() ) );
         getProperties().setProperty( ProviderParameterNames.PARALLEL_TIMEOUTFORCED_PROP,
-                Integer.toString( getParallelTestsTimeoutForcedInSeconds() ) );
+                Double.toString( getParallelTestsTimeoutForcedInSeconds() ) );
 
         String message =
             "parallel='" + usedParallel + '\'' + ", perCoreThreadCount=" + getPerCoreThreadCount() + ", threadCount="
@@ -2224,7 +2224,7 @@ public abstract class AbstractSurefireMojo
             {
                 return;
             }
-            if ( junitArtifact != null && !junit47Compatible )
+            if ( junitArtifact != null )
             {
                 throw new MojoFailureException( "groups/excludedGroups are specified but JUnit version on classpath"
                                                     + " is too old to support groups. Check your dependency:tree to see if your project is picking up an old junit version" );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
index 0b5a1af..22152f0 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireExecutionParameters.java
@@ -101,13 +101,13 @@ public interface SurefireExecutionParameters
 
     void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds );
 
-    int getParallelTestsTimeoutInSeconds();
+    double getParallelTestsTimeoutInSeconds();
 
-    void setParallelTestsTimeoutInSeconds( int parallelTestsTimeoutInSeconds );
+    void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds );
 
-    int getParallelTestsTimeoutForcedInSeconds();
+    double getParallelTestsTimeoutForcedInSeconds();
 
-    void setParallelTestsTimeoutForcedInSeconds( int parallelTestsTimeoutForcedInSeconds );
+    void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds );
 
     boolean isUseSystemClassLoader();
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator.java
index 03cbd4c..29fbf11 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator.java
@@ -54,6 +54,11 @@ public class ChecksumCalculator
         checksumItems.add( value );
     }
 
+    public void add( double value )
+    {
+        checksumItems.add( value );
+    }
+
     public void add( Map<?, ?> map )
     {
         if ( map != null )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
index 189161b..1477b23 100644
--- a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
+++ b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
@@ -122,24 +122,30 @@ public class SurefirePlugin
 
     /**
      * Stop executing queued parallel JUnit tests after a certain number of seconds.
+     * <br/>
+     * Example values: "3.5", "4"<br/>
+     * <br/>
      * If set to 0, wait forever, never timing out.
      * Makes sense with specified <code>parallel</code> different from "none".
      *
      * @since 2.16
      */
     @Parameter( property = "surefire.parallel.timeout" )
-    private int parallelTestsTimeoutInSeconds;
+    private double parallelTestsTimeoutInSeconds;
 
     /**
      * Stop executing queued parallel JUnit tests
      * and <em>interrupt</em> currently running tests after a certain number of seconds.
+     * <br/>
+     * Example values: "3.5", "4"<br/>
+     * <br/>
      * If set to 0, wait forever, never timing out.
      * Makes sense with specified <code>parallel</code> different from "none".
      *
      * @since 2.16
      */
     @Parameter( property = "surefire.parallel.forcedTimeout" )
-    private int parallelTestsTimeoutForcedInSeconds;
+    private double parallelTestsTimeoutForcedInSeconds;
     
     /**
      * A list of &lt;include> elements specifying the tests (by pattern) that should be included in testing. When not
@@ -447,19 +453,19 @@ public class SurefirePlugin
         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
     }
 
-    public int getParallelTestsTimeoutInSeconds() {
+    public double getParallelTestsTimeoutInSeconds() {
         return parallelTestsTimeoutInSeconds;
     }
 
-    public void setParallelTestsTimeoutInSeconds( int parallelTestsTimeoutInSeconds ) {
+    public void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds ) {
         this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
     }
 
-    public int getParallelTestsTimeoutForcedInSeconds() {
+    public double getParallelTestsTimeoutForcedInSeconds() {
         return parallelTestsTimeoutForcedInSeconds;
     }
 
-    public void setParallelTestsTimeoutForcedInSeconds( int parallelTestsTimeoutForcedInSeconds ) {
+    public void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds ) {
         this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm b/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
index 207364d..7b87379 100644
--- a/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
@@ -42,17 +42,58 @@ Fork Options and Parallel Test Execution
 * Parallel Test Execution
 
   Basically, there are two ways in Surefire to achieve parallel test execution.
+  
   The most obvious one is by using the <<<parallel>>> parameter. The possible
   values depend on the test provider used. For JUnit 4.7 and onwards, this may
-  be <<<methods>>>, <<<classes>>>, or <<<both>>>.
+  be <<<methods>>>, <<<classes>>>, <<<both>>>, <<<suites>>>,
+  <<<suitesAndClasses>>>, <<<suitesAndMethods>>>, <<<classesAndMethods>>>,
+  <<<all>>>.
+  As of surefire 2.16, the value "both" is deprecated but it still can be
+  used and behaves same as <<<classesAndMethods>>>.
 
   See the example pages for {{{./junit.html#Running_tests_in_parallel}JUnit}}
   and {{{./testng.html#Running_tests_in_parallel}TestNG}} for details.
 
-  The <extent> of the parallelism is configured using the parameters
-  <<<threadCount>>>, and optionally <<<perCoreThreadCount>>>, or
-  <<<useUnlimitedThreads>>>.
-
+  The <extent> of the parallelism is configured using the following parameters.
+  The parameter <<<useUnlimitedThreads>>> declares the unlimited number of
+  threads. Unless <<<useUnlimitedThreads>>> is set to "true", the parameter
+  <<<threadCount>>> can be used with the optional parameter
+  <<<perCoreThreadCount>>>.
+  The parameters <<<useUnlimitedThreads>>>, <<<threadCount>>> make sense with
+  thereinbefore value specified in the parameter <<<parallel>>>.
+  
+  You can impose thread-count limitations on suites, classes or methods if you
+  configure some of the parameters <<<threadCountSuites>>>,
+  <<<threadCountClasses>>> or <<<threadCountMethods>>>.
+  If the only <<<threadCount>>> is specified, the surefire attempts to estimate
+  thread-counts for suites, classes and methods and reuse the threads in favor
+  of parallel methods (possibly increasing concurrent methods).
+  
+  As an example with unlimited number of threads, there is maximum of three
+  concurrent threads to execute suites:
+  parallel = all, useUnlimitedThreads = true, threadCountSuites = 3.
+  
+  In the second example, the number of concurrent methods is not strictly
+  limited:
+  parallel = classesAndMethods, threadCount = 8, threadCountClasses = 3.
+  Here the number of parallel methods is varying from 5 to 7.
+  Similarily with parallel = all, but the sum of <<<threadCountSuites>>> and
+  <<<threadCountClasses>>> must not excit certain <<<threadCount>>> - 1.
+  Other combinations are possible with unspecified thread-count leaf. Make sure
+  that the leaf is last from the order suites-classes-methods in <<<parallel>>>.
+  
+  In the third example the thread-counts represent a ratio, e.g. for
+  parallel = all, threadCount = 16, threadCountSuites = 2,
+  threadCountClasses = 3, threadCountMethods = 5. Thus the concurrent suites
+  will be 20%, concurrent classes 30%, and concurrent methods 50%.
+  
+  Finally, the <<<threadCount>>> and <<<useUnlimitedThreads>>> may not be
+  necessarily configured if the equivalent thread-counts are specified for the
+  value in <<<parallel>>>.
+  
+  The surefire is always trying to reuse threads, optimize the thread-counts,
+  and prefers thread fairness.
+  
   <<The important thing to remember>> with the <<<parallel>>> option is: the
   concurrency happens within the same JVM process. That is efficient in terms of
   memory and execution time, but you may be more vulnerable towards race

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/maven-surefire-plugin/src/site/apt/examples/junit.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/junit.apt.vm b/maven-surefire-plugin/src/site/apt/examples/junit.apt.vm
index 74e32cb..980779a 100644
--- a/maven-surefire-plugin/src/site/apt/examples/junit.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/junit.apt.vm
@@ -142,6 +142,10 @@ else
   This is particularly useful for slow tests that can have high concurrency.
 
   As of surefire 2.7, no additional dependencies are needed to use the full set of options with parallel.
+  As of surefire 2.16, new thread-count attributes are introduced, namely <<<threadCountSuites>>>, <<<threadCountClasses>>> and
+  <<<threadCountMethods>>>. Additionally new attributes, <<<parallelTestsTimeoutInSeconds>>> and
+  <<<parallelTestsTimeoutForcedInSeconds>>>, are used to shutdown the parallel execution after an elapsed timeout, and 
+  the attribute "parallel" specifies new values.
   
   See also {{{./fork-options-and-parallel-execution.html}Fork Options and Parallel Test Execution}}.
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47ParallelIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47ParallelIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47ParallelIT.java
new file mode 100644
index 0000000..e236e54
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47ParallelIT.java
@@ -0,0 +1,495 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * 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.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.junit.Test;
+
+/**
+ * Testing JUnitCoreWrapper with ParallelComputerBuilder.
+ *
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class JUnit47ParallelIT
+    extends SurefireJUnit4IntegrationTestCase
+{
+
+    @Test
+    public void unknownThreadCountSuites()
+    {
+        unpack().parallelSuites().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use threadCount or threadCountSuites > 0 or useUnlimitedThreads=true for parallel='suites'" );
+    }
+
+    @Test
+    public void unknownThreadCountClasses()
+    {
+        unpack().parallelClasses().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use threadCount or threadCountClasses > 0 or useUnlimitedThreads=true for parallel='classes'" );
+    }
+
+    @Test
+    public void unknownThreadCountMethods()
+    {
+        unpack().parallelMethods().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use threadCount or threadCountMethods > 0 or useUnlimitedThreads=true for parallel='methods'" );
+
+    }
+
+    @Test
+    public void unknownThreadCountBoth()
+    {
+        unpack().parallelBoth().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use useUnlimitedThreads=true, " +
+                "or only threadCount > 0, " +
+                "or (threadCountClasses > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountClasses > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountClasses > 0 and threadCount > threadCountClasses) " +
+                "for parallel='both' or parallel='classesAndMethods'" );
+    }
+
+    @Test
+    public void unknownThreadCountAll()
+    {
+        unpack().parallelAll().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use useUnlimitedThreads=true, " +
+                "or only threadCount > 0, " +
+                "or (threadCountSuites > 0 and threadCountClasses > 0 and threadCountMethods > 0), " +
+                "or every thread-count is specified, " +
+                "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0 " +
+                "and threadCount > threadCountSuites + threadCountClasses) " +
+                "for parallel='all'" );
+    }
+
+    @Test
+    public void unknownThreadCountSuitesAndClasses()
+    {
+        unpack().parallelSuitesAndClasses().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use useUnlimitedThreads=true, " +
+                "or only threadCount > 0, " +
+                "or (threadCountSuites > 0 and threadCountClasses > 0), " +
+                "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0) " +
+                "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) " +
+                "for parallel='suitesAndClasses' or 'both'" );
+    }
+
+    @Test
+    public void unknownThreadCountSuitesAndMethods()
+    {
+        unpack().parallelSuitesAndMethods().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use useUnlimitedThreads=true, " +
+                "or only threadCount > 0, " +
+                "or (threadCountSuites > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountSuites > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) " +
+                "for parallel='suitesAndMethods'" );
+    }
+
+    @Test
+    public void unknownThreadCountClassesAndMethods()
+    {
+        unpack().parallelClassesAndMethods().setTestToRun( "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "Use useUnlimitedThreads=true, " +
+                "or only threadCount > 0, " +
+                "or (threadCountClasses > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountClasses > 0 and threadCountMethods > 0), " +
+                "or (threadCount > 0 and threadCountClasses > 0 and threadCount > threadCountClasses) " +
+                "for parallel='both' or parallel='classesAndMethods'" );
+    }
+
+    @Test
+    public void serial()
+    {
+        // takes 7.2 sec
+        unpack().setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsSuites1()
+    {
+        // takes 3.6 sec
+        unpack().parallelSuites().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsSuites2()
+    {
+        // takes 3.6 sec
+        unpack().parallelSuites().useUnlimitedThreads().threadCountSuites( 5 ).setTestToRun( "Suite*Test" )
+            .executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsClasses1()
+    {
+        // takes 1.8 sec
+        unpack().parallelClasses().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsClasses2()
+    {
+        // takes 1.8 sec
+        unpack().parallelClasses().useUnlimitedThreads().threadCountClasses( 5 ).setTestToRun( "Suite*Test" )
+            .executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsMethods1()
+    {
+        // takes 2.4 sec
+        unpack().parallelMethods().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void useUnlimitedThreadsMethods2()
+    {
+        // takes 2.4 sec
+        unpack().parallelMethods().useUnlimitedThreads().threadCountMethods( 5 ).setTestToRun( "Suite*Test" )
+            .executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsSuitesAndClasses1()
+    {
+        // takes 0.9 sec
+        unpack().parallelSuitesAndClasses().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+        //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsSuitesAndClasses2()
+    {
+        // takes 0.9 sec
+        // 1.8 sec with 4 parallel classes
+        unpack().parallelSuitesAndClasses().useUnlimitedThreads().threadCountSuites( 5 ).threadCountClasses( 15 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsSuitesAndMethods1()
+    {
+        // takes 1.2 sec
+        unpack().parallelSuitesAndMethods().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsSuitesAndMethods2()
+    {
+        // takes 1.2 sec
+        unpack().parallelSuitesAndMethods().useUnlimitedThreads().threadCountSuites( 5 ).threadCountMethods( 15 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsClassesAndMethods1()
+    {
+        // takes 0.6 sec
+        unpack().parallelClassesAndMethods().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsClassesAndMethods2()
+    {
+        // takes 0.6 sec
+        unpack().parallelClassesAndMethods().useUnlimitedThreads().threadCountClasses( 5 ).threadCountMethods( 15 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsAll1()
+    {
+        // takes 0.3 sec
+        unpack().parallelAll().useUnlimitedThreads().setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void unlimitedThreadsAll2()
+    {
+        // takes 0.3 sec
+        unpack().parallelAll().useUnlimitedThreads().threadCountSuites( 5 ).threadCountClasses( 15 )
+            .threadCountMethods( 30 ).setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountSuites()
+    {
+        // takes 3.6 sec
+        unpack().parallelSuites().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountClasses()
+    {
+        // takes 3.6 sec for single core
+        // takes 1.8 sec for double core
+        unpack().parallelClasses().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountMethods()
+    {
+        // takes 2.4 sec
+        unpack().parallelMethods().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountClassesAndMethodsOneCore()
+    {
+        // takes 4.8 sec
+        unpack().disablePerCoreThreadCount().parallelClassesAndMethods().threadCount( 3 ).setTestToRun( "Suite*Test" )
+            .executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountClassesAndMethods()
+    {
+        // takes 2.4 sec for double core CPU
+        unpack().parallelClassesAndMethods().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()
+        //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountSuitesAndMethods()
+    {
+        // usually 24 times 0.3 sec = 7.2 sec with one core CPU
+        // takes 1.8 sec for double core CPU
+        unpack().parallelSuitesAndMethods().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountSuitesAndClasses()
+    {
+        unpack().parallelSuitesAndClasses().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void threadCountAll()
+    {
+        unpack().parallelAll().threadCount( 3 ).setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void everyThreadCountSuitesAndClasses()
+    {
+        // takes 1.8 sec for double core CPU
+        unpack().parallelSuitesAndClasses().threadCount( 3 ).threadCountSuites( 34 ).threadCountClasses( 66 )
+            .setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void everyThreadCountSuitesAndMethods()
+    {
+        // takes 1.8 sec for double core CPU
+        unpack().parallelSuitesAndMethods().threadCount( 3 ).threadCountSuites( 34 ).threadCountMethods( 66 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void everyThreadCountClassesAndMethods()
+    {
+        // takes 1.8 sec for double core CPU
+        unpack().parallelClassesAndMethods().threadCount( 3 ).threadCountClasses( 34 ).threadCountMethods( 66 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void everyThreadCountAll()
+    {
+        // takes 2.4 sec for double core CPU
+        unpack().parallelAll().threadCount( 3 ).threadCountSuites( 17 ).threadCountClasses( 34 ).threadCountMethods(
+            49 ).setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void reusableThreadCountSuitesAndClasses()
+    {
+        // 4 * cpu to 5 * cpu threads to run test classes
+        // takes cca 1.8 sec
+        unpack().parallelSuitesAndClasses().disablePerCoreThreadCount().threadCount( 6 ).threadCountSuites( 2 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void reusableThreadCountSuitesAndMethods()
+    {
+        // 4 * cpu to 5 * cpu threads to run test methods
+        // takes cca 1.8 sec
+        unpack().parallelSuitesAndMethods().disablePerCoreThreadCount().threadCount( 6 ).threadCountSuites( 2 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void reusableThreadCountClassesAndMethods()
+    {
+        // 4 * cpu to 5 * cpu threads to run test methods
+        // takes cca 1.8 sec
+        unpack().parallelClassesAndMethods().disablePerCoreThreadCount().threadCount( 6 ).threadCountClasses( 2 )
+            .setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void reusableThreadCountAll()
+    {
+        // 8 * cpu to 13 * cpu threads to run test methods
+        // takes 0.9 sec
+        unpack().parallelAll().disablePerCoreThreadCount().threadCount( 14 ).threadCountSuites( 2 ).threadCountClasses(
+            4 ).setTestToRun( "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void suites()
+    {
+        // takes 3.6 sec
+        unpack().parallelSuites().threadCountSuites( 5 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void classes()
+    {
+        // takes 1.8 sec on any CPU because the suites are running in a sequence
+        unpack().parallelClasses().threadCountClasses( 5 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void methods()
+    {
+        // takes 2.4 sec on any CPU because every class has only three methods
+        // and the suites and classes are running in a sequence
+        unpack().parallelMethods().threadCountMethods( 5 ).setTestToRun( "Suite*Test" ).executeTest()
+            //.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void suitesAndClasses()
+    {
+        // takes 0.9 sec
+        unpack().parallelSuitesAndClasses().threadCountSuites( 5 ).threadCountClasses( 15 ).setTestToRun(
+            "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void suitesAndMethods()
+    {
+        // takes 1.2 sec on any CPU
+        unpack().parallelSuitesAndMethods().threadCountSuites( 5 ).threadCountMethods( 15 ).setTestToRun(
+            "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void classesAndMethods()
+    {
+        // takes 0.6 sec on any CPU
+        unpack().parallelClassesAndMethods().threadCountClasses( 5 ).threadCountMethods( 15 ).setTestToRun(
+            "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void all()
+    {
+        // takes 0.3 sec on any CPU
+        unpack().parallelAll().threadCountSuites( 5 ).threadCountClasses( 15 ).threadCountMethods( 30 ).setTestToRun(
+            "Suite*Test" ).executeTest()//.verifyErrorFree( 24 )
+        ;
+    }
+
+    @Test
+    public void shutdown()
+    {
+        // executes for 2.5 sec until timeout has elapsed
+        unpack().parallelMethods().threadCountMethods( 2 ).parallelTestsTimeoutInSeconds( 2.5d ).setTestToRun(
+            "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "The test run has finished abruptly after timeout of 2.5 seconds." );
+    }
+
+    @Test
+    public void forcedShutdown()
+    {
+        // executes for 2.5 sec until timeout has elapsed
+        unpack().parallelMethods().threadCountMethods( 2 ).parallelTestsTimeoutForcedInSeconds( 2.5d ).setTestToRun(
+            "TestClass" ).failNever().executeTest().verifyTextInLog(
+            "The test run has finished abruptly after timeout of 2.5 seconds." );
+    }
+
+    @Test
+    public void timeoutAndForcedShutdown()
+    {
+        // executes for one sec until timeout has elapsed
+        unpack().parallelMethods().threadCountMethods( 2 ).parallelTestsTimeoutInSeconds( 1 )
+            .parallelTestsTimeoutForcedInSeconds( 2.5d ).setTestToRun( "TestClass" ).failNever().executeTest()
+            .verifyTextInLog( "The test run has finished abruptly after timeout of 1.0 seconds." );
+    }
+
+    private SurefireLauncher unpack()
+    {
+        return unpack( "junit47-parallel" );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
index e0befcc..8d4a385 100755
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
@@ -339,6 +339,11 @@ public class MavenLauncher
         return addGoal( "-D" + variable + "=" + value );
     }
 
+    public MavenLauncher sysProp( String variable, double value )
+    {
+        return addGoal( "-D" + variable + "=" + value );
+    }
+
     public MavenLauncher showExceptionMessages()
     {
         addCliOption( "-e" );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
index 7b65783..3ac3e20 100755
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
@@ -313,14 +313,18 @@ public class SurefireLauncher
         return surefireVersion;
     }
 
-    public SurefireLauncher parallel( String parallel )
+    public SurefireLauncher disablePerCoreThreadCount()
     {
+        mavenLauncher.sysProp( "perCoreThreadCount", false );
+        return this;
+    }
 
+    public SurefireLauncher parallel( String parallel )
+    {
         mavenLauncher.sysProp( "parallel", parallel );
         return this;
     }
 
-
     public SurefireLauncher parallelSuites()
     {
         return parallel( "suites" );
@@ -336,6 +340,66 @@ public class SurefireLauncher
         return parallel( "methods" );
     }
 
+    public SurefireLauncher parallelBoth()
+    {
+        return parallel( "both" );
+    }
+
+    public SurefireLauncher parallelSuitesAndClasses()
+    {
+        return parallel( "suitesAndClasses" );
+    }
+
+    public SurefireLauncher parallelSuitesAndMethods()
+    {
+        return parallel( "suitesAndMethods" );
+    }
+
+    public SurefireLauncher parallelClassesAndMethods()
+    {
+        return parallel( "classesAndMethods" );
+    }
+
+    public SurefireLauncher parallelAll()
+    {
+        return parallel( "all" );
+    }
+
+    public SurefireLauncher useUnlimitedThreads()
+    {
+        mavenLauncher.sysProp( "useUnlimitedThreads", true );
+        return this;
+    }
+
+    public SurefireLauncher threadCountSuites( int count )
+    {
+        mavenLauncher.sysProp( "threadCountSuites", count );
+        return this;
+    }
+
+    public SurefireLauncher threadCountClasses( int count )
+    {
+        mavenLauncher.sysProp( "threadCountClasses", count );
+        return this;
+    }
+
+    public SurefireLauncher threadCountMethods( int count )
+    {
+        mavenLauncher.sysProp( "threadCountMethods", count );
+        return this;
+    }
+
+    public SurefireLauncher parallelTestsTimeoutInSeconds( double timeout )
+    {
+        mavenLauncher.sysProp( "surefire.parallel.timeout", timeout );
+        return this;
+    }
+
+    public SurefireLauncher parallelTestsTimeoutForcedInSeconds( double timeout )
+    {
+        mavenLauncher.sysProp( "surefire.parallel.forcedTimeout", timeout );
+        return this;
+    }
 
     public SurefireLauncher sysProp( String variable, String value )
     {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/pom.xml b/surefire-integration-tests/src/test/resources/junit47-parallel/pom.xml
new file mode 100644
index 0000000..d8de300
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/pom.xml
@@ -0,0 +1,33 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.plugins.surefire</groupId>
+  <artifactId>junit47-parallel</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <name>junit47-parallel</name>
+  <url>http://maven.apache.org</url>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.8.1</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>${surefire.version}</version>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite1Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite1Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite1Test.java
new file mode 100644
index 0000000..99419fe
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite1Test.java
@@ -0,0 +1,39 @@
+package surefireparallel;
+
+/*
+ * 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.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+@RunWith( Suite.class )
+@Suite.SuiteClasses(
+    {
+        Waiting1Test.class,
+        Waiting2Test.class,
+        Waiting3Test.class,
+        Waiting4Test.class
+    })
+public class Suite1Test
+{
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite2Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite2Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite2Test.java
new file mode 100644
index 0000000..32814ff
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Suite2Test.java
@@ -0,0 +1,39 @@
+package surefireparallel;
+
+/*
+ * 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.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+@RunWith( Suite.class )
+@Suite.SuiteClasses(
+    {
+        Waiting5Test.class,
+        Waiting6Test.class,
+        Waiting7Test.class,
+        Waiting8Test.class
+    })
+public class Suite2Test
+{
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/TestClass.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/TestClass.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/TestClass.java
new file mode 100644
index 0000000..3b1f842
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/TestClass.java
@@ -0,0 +1,53 @@
+package surefireparallel;
+
+/*
+ * 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.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class TestClass
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 5000L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 5000L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 5000L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting1Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting1Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting1Test.java
new file mode 100644
index 0000000..1d58841
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting1Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting1Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting2Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting2Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting2Test.java
new file mode 100644
index 0000000..55da772
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting2Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting2Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting3Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting3Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting3Test.java
new file mode 100644
index 0000000..5098fd4
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting3Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting3Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting4Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting4Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting4Test.java
new file mode 100644
index 0000000..8418448
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting4Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting4Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting5Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting5Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting5Test.java
new file mode 100644
index 0000000..2b99160
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting5Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting5Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting6Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting6Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting6Test.java
new file mode 100644
index 0000000..9ae9c01
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting6Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting6Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting7Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting7Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting7Test.java
new file mode 100644
index 0000000..ca00a6a
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting7Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting7Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting8Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting8Test.java b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting8Test.java
new file mode 100644
index 0000000..96d1c66
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-parallel/src/test/java/surefireparallel/Waiting8Test.java
@@ -0,0 +1,50 @@
+package surefireparallel;
+
+/*
+ * 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;
+
+/**
+ * @author Tibor Digana (tibor17)
+ * @since 2.16
+ */
+public class Waiting8Test
+{
+    @Test
+    public void a()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void b()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+
+    @Test
+    public void c()
+        throws InterruptedException
+    {
+        Thread.sleep( 300L );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreParameters.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreParameters.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreParameters.java
index 157ed58..8421751 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreParameters.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreParameters.java
@@ -22,6 +22,7 @@ package org.apache.maven.surefire.junitcore;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Properties;
+
 import org.apache.maven.surefire.booter.ProviderParameterNames;
 
 /**
@@ -29,24 +30,6 @@ import org.apache.maven.surefire.booter.ProviderParameterNames;
  */
 class JUnitCoreParameters
 {
-    private final String parallel;
-
-    private final Boolean perCoreThreadCount;
-
-    private final int threadCount;
-
-    private final int threadCountSuites;
-
-    private final int threadCountClasses;
-
-    private final int threadCountMethods;
-
-    private final int parallelTestsTimeoutInSeconds;
-
-    private final int parallelTestsTimeoutForcedInSeconds;
-
-    private final Boolean useUnlimitedThreads;
-
     public static final String PARALLEL_KEY = ProviderParameterNames.PARALLEL_PROP;
 
     public static final String PERCORETHREADCOUNT_KEY = "perCoreThreadCount";
@@ -65,6 +48,24 @@ class JUnitCoreParameters
 
     public static final String PARALLEL_TIMEOUTFORCED_KEY = ProviderParameterNames.PARALLEL_TIMEOUTFORCED_PROP;
 
+    private final String parallel;
+
+    private final Boolean perCoreThreadCount;
+
+    private final int threadCount;
+
+    private final int threadCountSuites;
+
+    private final int threadCountClasses;
+
+    private final int threadCountMethods;
+
+    private final double parallelTestsTimeoutInSeconds;
+
+    private final double parallelTestsTimeoutForcedInSeconds;
+
+    private final Boolean useUnlimitedThreads;
+
     public JUnitCoreParameters( Properties properties )
     {
         parallel = properties.getProperty( PARALLEL_KEY, "none" ).toLowerCase();
@@ -74,8 +75,10 @@ class JUnitCoreParameters
         threadCountClasses = Integer.valueOf( properties.getProperty( THREADCOUNTCLASSES_KEY, "0" ) );
         threadCountSuites = Integer.valueOf( properties.getProperty( THREADCOUNTSUITES_KEY, "0" ) );
         useUnlimitedThreads = Boolean.valueOf( properties.getProperty( USEUNLIMITEDTHREADS_KEY, "false" ) );
-        parallelTestsTimeoutInSeconds = Integer.valueOf( properties.getProperty( PARALLEL_TIMEOUT_KEY, "0" ) );
-        parallelTestsTimeoutForcedInSeconds = Integer.valueOf( properties.getProperty( PARALLEL_TIMEOUTFORCED_KEY, "0" ) );
+        parallelTestsTimeoutInSeconds =
+            Math.max( Double.valueOf( properties.getProperty( PARALLEL_TIMEOUT_KEY, "0" ) ), 0 );
+        parallelTestsTimeoutForcedInSeconds =
+            Math.max( Double.valueOf( properties.getProperty( PARALLEL_TIMEOUTFORCED_KEY, "0" ) ), 0 );
     }
 
     private static Collection<String> lowerCase( String... elements )
@@ -95,14 +98,14 @@ class JUnitCoreParameters
 
     public boolean isParallelMethod()
     {
-        return isAllParallel()
-                || lowerCase( "both", "methods", "suitesAndMethods", "classesAndMethods" ).contains( parallel );
+        return isAllParallel() || lowerCase( "both", "methods", "suitesAndMethods", "classesAndMethods" ).contains(
+            parallel );
     }
 
     public boolean isParallelClasses()
     {
-        return isAllParallel()
-                || lowerCase( "both", "classes", "suitesAndClasses", "classesAndMethods" ).contains( parallel );
+        return isAllParallel() || lowerCase( "both", "classes", "suitesAndClasses", "classesAndMethods" ).contains(
+            parallel );
     }
 
     public boolean isParallelSuites()
@@ -149,12 +152,12 @@ class JUnitCoreParameters
         return useUnlimitedThreads;
     }
 
-    public int getParallelTestsTimeoutInSeconds()
+    public double getParallelTestsTimeoutInSeconds()
     {
         return parallelTestsTimeoutInSeconds;
     }
 
-    public int getParallelTestsTimeoutForcedInSeconds()
+    public double getParallelTestsTimeoutForcedInSeconds()
     {
         return parallelTestsTimeoutForcedInSeconds;
     }
@@ -174,6 +177,6 @@ class JUnitCoreParameters
     {
         return "parallel='" + parallel + '\'' + ", perCoreThreadCount=" + perCoreThreadCount + ", threadCount="
             + threadCount + ", useUnlimitedThreads=" + useUnlimitedThreads + ", threadCountSuites=" + threadCountSuites
-                + ", threadCountClasses=" + threadCountClasses + ", threadCountMethods=" + threadCountMethods;
+            + ", threadCountClasses=" + threadCountClasses + ", threadCountMethods=" + threadCountMethods;
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/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 45cf34c..e124f6e 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,12 +19,7 @@ package org.apache.maven.surefire.junitcore;
  * under the License.
  */
 
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
-import java.util.TreeSet;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
 
 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
 import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
@@ -32,7 +27,6 @@ import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.apache.maven.surefire.util.TestsToRun;
 
 import org.junit.runner.Computer;
-import org.junit.runner.Description;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Request;
 import org.junit.runner.Result;
@@ -49,51 +43,28 @@ import org.junit.runner.notification.RunListener;
 
 class JUnitCoreWrapper
 {
-    private static 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;
-        }
-    }
-
     public static void execute( TestsToRun testsToRun, JUnitCoreParameters jUnitCoreParameters,
                                 List<RunListener> listeners, Filter filter )
         throws TestSetFailedException
     {
-        ComputerWrapper computerWrapper = createComputer( jUnitCoreParameters );
+        Computer computer = createComputer( jUnitCoreParameters );
         JUnitCore junitCore = createJUnitCore( listeners );
         if ( testsToRun.allowEagerReading() )
         {
-            executeEager( testsToRun, filter, computerWrapper.getComputer(), junitCore );
+            executeEager( testsToRun, filter, computer, junitCore );
         }
         else
         {
-            exeuteLazy( testsToRun, filter, computerWrapper.getComputer(), junitCore );
+            exeuteLazy( testsToRun, filter, computer, junitCore );
         }
 
-        String timeoutMessage = computerWrapper.describeElapsedTimeout();
-        if ( timeoutMessage.length() != 0 )
+        if ( computer instanceof ParallelComputer )
         {
-            throw new TestSetFailedException( timeoutMessage );
+            String timeoutMessage = ( (ParallelComputer) computer ).describeElapsedTimeout();
+            if ( timeoutMessage.length() != 0 )
+            {
+                throw new TestSetFailedException( timeoutMessage );
+            }
         }
     }
 
@@ -107,15 +78,15 @@ class JUnitCoreWrapper
         return junitCore;
     }
 
-    private static void executeEager(TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore)
-            throws TestSetFailedException 
+    private static void executeEager( TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore )
+        throws TestSetFailedException
     {
         Class[] tests = testsToRun.getLocatedClasses();
         createRequestAndRun( filter, computer, junitCore, tests );
     }
 
-    private static void exeuteLazy(TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore)
-            throws TestSetFailedException
+    private static void exeuteLazy( TestsToRun testsToRun, Filter filter, Computer computer, JUnitCore junitCore )
+        throws TestSetFailedException
     {
         // in order to support LazyTestsToRun, the iterator must be used
         for ( Class clazz : testsToRun )
@@ -124,8 +95,9 @@ class JUnitCoreWrapper
         }
     }
 
-    private static void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, Class<?>... classesToRun )
-            throws TestSetFailedException
+    private static void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore,
+                                             Class<?>... classesToRun )
+        throws TestSetFailedException
     {
         Request req = Request.classes( computer, classesToRun );
         if ( filter != null )
@@ -142,110 +114,37 @@ class JUnitCoreWrapper
         JUnit4RunListener.rethrowAnyTestMechanismFailures( run );
     }
 
-    private static ComputerWrapper createComputer( JUnitCoreParameters parameters )
+    private static Computer createComputer( JUnitCoreParameters parameters )
         throws TestSetFailedException
     {
-        return parameters.isNoThreading() ? new ComputerWrapper( Computer.serial() ) : createParallelComputer( parameters );
+        return parameters.isNoThreading()
+            ? Computer.serial()
+            : ParallelComputerFactory.createParallelComputer( parameters );
     }
 
-    private static ComputerWrapper createParallelComputer( JUnitCoreParameters parameters )
-            throws TestSetFailedException
-    {
-        ParallelComputer pc = ParallelComputerFactory.createParallelComputer( parameters );
-
-        int timeout = parameters.getParallelTestsTimeoutInSeconds();
-
-        int timeoutForced = parameters.getParallelTestsTimeoutForcedInSeconds();
-
-        Future<Collection<Description>> testsBeforeShutdown =
-                timeout > 0 ? pc.scheduleShutdown( timeout, TimeUnit.SECONDS ) : null;
-
-        Future<Collection<Description>> testsBeforeForcedShutdown =
-                timeoutForced > 0 ? pc.scheduleForcedShutdown( timeoutForced, TimeUnit.SECONDS ) : null;
-
-        return new ComputerWrapper( pc, timeout, testsBeforeShutdown, timeoutForced, testsBeforeForcedShutdown );
-    }
-
-    private static class ComputerWrapper
+    private static class FilteringRequest
+        extends Request
     {
-        private final Computer computer;
-        private final int timeout;
-        private final int timeoutForced;
-        private final Future<Collection<Description>> testsBeforeShutdown;
-        private final Future<Collection<Description>> testsBeforeForcedShutdown;
-
-        ComputerWrapper( Computer computer )
-        {
-            this( computer, 0, null, 0, null );
-        }
-
-        ComputerWrapper( Computer computer,
-                         int timeout, Future<Collection<Description>> testsBeforeShutdown,
-                         int timeoutForced, Future<Collection<Description>> testsBeforeForcedShutdown )
-        {
-            this.computer = computer;
-            this.timeout = timeout;
-            this.testsBeforeShutdown = testsBeforeShutdown;
-            this.timeoutForced = timeoutForced;
-            this.testsBeforeForcedShutdown = testsBeforeForcedShutdown;
-        }
-
-        Computer getComputer()
-        {
-            return computer;
-        }
+        private Runner filteredRunner;
 
-        String describeElapsedTimeout() throws TestSetFailedException
+        public FilteringRequest( Request req, Filter filter )
         {
-            TreeSet<String> executedTests = new TreeSet<String>();
-            if ( timeout > 0 )
-            {
-                executedTests.addAll( printShutdownHook( testsBeforeShutdown ) );
-            }
-
-            if ( timeoutForced > 0 )
+            try
             {
-                executedTests.addAll( printShutdownHook( testsBeforeForcedShutdown ) );
+                Runner runner = req.getRunner();
+                filter.apply( runner );
+                filteredRunner = runner;
             }
-
-            StringBuilder msg = new StringBuilder();
-            if ( !executedTests.isEmpty() )
+            catch ( NoTestsRemainException e )
             {
-                msg.append( "The test run has finished abruptly after timeout of " );
-                msg.append( Math.min( timeout, timeoutForced ) );
-                msg.append( " seconds.\n" );
-                msg.append( "These tests were executed in prior of the shutdown operation:\n" );
-                for ( String executedTest : executedTests )
-                {
-                    msg.append( executedTest ).append( "\n" );
-                }
+                filteredRunner = null;
             }
-            return msg.toString();
         }
 
-        static Collection<String> printShutdownHook( Future<Collection<Description>> future )
-                throws TestSetFailedException
+        @Override
+        public Runner getRunner()
         {
-            if ( !future.isCancelled() && future.isDone() )
-            {
-                try
-                {
-                    TreeSet<String> executedTests = new TreeSet<String>();
-                    for ( Description executedTest : future.get() )
-                    {
-                        if ( executedTest != null && executedTest.getDisplayName() != null )
-                        {
-                            executedTests.add( executedTest.getDisplayName() );
-                        }
-                    }
-                    return executedTests;
-                }
-                catch ( Exception e )
-                {
-                    throw new TestSetFailedException( e );
-                }
-            }
-            return Collections.emptySet();
+            return filteredRunner;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a9d511a0/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
index dcf8615..db2ff05 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
@@ -76,11 +76,11 @@ public class NonConcurrentRunListener
     public void testStarted( Description description )
         throws Exception
     {
-        finishLastTestSetIfNeccessary( description );
+        finishLastTestSetIfNecessary( description );
         super.testStarted( description );
     }
 
-    private void finishLastTestSetIfNeccessary( Description description )
+    private void finishLastTestSetIfNecessary( Description description )
     {
         if ( describesNewTestSet( description ) )
         {
@@ -125,7 +125,7 @@ public class NonConcurrentRunListener
     public void testIgnored( Description description )
         throws Exception
     {
-        finishLastTestSetIfNeccessary( description );
+        finishLastTestSetIfNecessary( description );
 
         super.testIgnored( description );
         this.lastFinishedDescription = description;