You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2019/07/24 15:01:08 UTC

[maven-surefire] branch master updated (2d09927 -> bca90b2)

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.


    from 2d09927  investigating build failure: removed jenkinsNotify()
     add 8efc903  fixed collisions between test methods in ForkConfigurationTest
     new bca90b2  [SUREFIRE-1675] Forked JVM terminates with 'halt' when another module's tests fail

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Jenkinsfile                                        |  12 +-
 maven-failsafe-plugin/pom.xml                      |   2 +-
 ...ooterDeserializerProviderConfigurationTest.java |  26 +++-
 ...BooterDeserializerStartupConfigurationTest.java |  29 ++++-
 .../booterclient/ForkConfigurationTest.java        |  93 +++++++------
 .../maven/surefire/booter/CommandReader.java       |   3 +-
 .../apache/maven/surefire/booter/ForkedBooter.java | 134 +++++++++++++++----
 .../surefire/booter/ForkedBooterMockTest.java      | 134 +++++++++++++++++++
 .../maven/surefire/booter/ForkedBooterTest.java    | 144 +++++++++++++++++++++
 .../maven/surefire/booter/JUnit4SuiteTest.java     |   2 +
 ...Surefire946KillMainProcessInReusableForkIT.java | 118 +++++++++++++----
 .../pom.xml                                        |  44 +++----
 .../src/main/java/dummy/DummyClass.java}           |  17 +--
 .../pom.xml                                        |   7 +
 .../test/java/junit44/environment/Basic01Test.java |   2 +
 .../test/java/junit44/environment/Basic02Test.java |   2 +
 .../test/java/junit44/environment/Basic03Test.java |   2 +
 .../test/java/junit44/environment/Basic04Test.java |   2 +
 .../test/java/junit44/environment/Basic05Test.java |   2 +
 .../test/java/junit44/environment/Basic06Test.java |   2 +
 .../test/java/junit44/environment/Basic07Test.java |   2 +
 .../test/java/junit44/environment/Basic08Test.java |   2 +
 .../test/java/junit44/environment/Basic09Test.java |   2 +
 .../test/java/junit44/environment/Basic10Test.java |   2 +
 .../surefire-946-self-destruct-plugin/pom.xml      |   6 -
 25 files changed, 652 insertions(+), 139 deletions(-)
 create mode 100644 surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
 create mode 100644 surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
 copy surefire-its/src/test/resources/{surefire-931-provider-failure => surefire-946-dummy-dependency}/pom.xml (50%)
 copy surefire-its/src/test/{java/org/apache/maven/surefire/its/RunOrderParallelForksIT.java => resources/surefire-946-dummy-dependency/src/main/java/dummy/DummyClass.java} (83%)


[maven-surefire] 01/01: [SUREFIRE-1675] Forked JVM terminates with 'halt' when another module's tests fail

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit bca90b23e264bb21db9c447f22f039d0cb5a0c1f
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Jul 20 14:55:27 2019 +0200

    [SUREFIRE-1675] Forked JVM terminates with 'halt' when another module's tests fail
---
 Jenkinsfile                                        |  12 +-
 maven-failsafe-plugin/pom.xml                      |   2 +-
 .../maven/surefire/booter/CommandReader.java       |   3 +-
 .../apache/maven/surefire/booter/ForkedBooter.java | 134 +++++++++++++++----
 .../surefire/booter/ForkedBooterMockTest.java      | 134 +++++++++++++++++++
 .../maven/surefire/booter/ForkedBooterTest.java    | 144 +++++++++++++++++++++
 .../maven/surefire/booter/JUnit4SuiteTest.java     |   2 +
 ...Surefire946KillMainProcessInReusableForkIT.java | 118 +++++++++++++----
 .../surefire-946-dummy-dependency/pom.xml          |  39 ++++++
 .../src/main/java/dummy/DummyClass.java}           |  31 ++---
 .../pom.xml                                        |   7 +
 .../test/java/junit44/environment/Basic01Test.java |   2 +
 .../test/java/junit44/environment/Basic02Test.java |   2 +
 .../test/java/junit44/environment/Basic03Test.java |   2 +
 .../test/java/junit44/environment/Basic04Test.java |   2 +
 .../test/java/junit44/environment/Basic05Test.java |   2 +
 .../test/java/junit44/environment/Basic06Test.java |   2 +
 .../test/java/junit44/environment/Basic07Test.java |   2 +
 .../test/java/junit44/environment/Basic08Test.java |   2 +
 .../test/java/junit44/environment/Basic09Test.java |   2 +
 .../test/java/junit44/environment/Basic10Test.java |   2 +
 .../surefire-946-self-destruct-plugin/pom.xml      |   6 -
 22 files changed, 570 insertions(+), 82 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 175c763..0abf4ba 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -30,10 +30,10 @@ properties(
     ]
 )
 
-final def oses = ['linux':'ubuntu && !H24', 'windows':'Windows && !windows-2016-1']
+final def oses = ['linux':'ubuntu', 'windows':'Windows']
 final def mavens = env.BRANCH_NAME == 'master' ? ['3.6.x', '3.2.x'] : ['3.6.x']
 // all non-EOL versions and the first EA
-final def jdks = [13, 12, 11, 8, 7]
+final def jdks = [13, 12, 11, 8]
 
 final def options = ['-e', '-V', '-B', '-nsu', '-P', 'run-its']
 final def goals = ['clean', 'install']
@@ -109,7 +109,7 @@ timeout(time: 12, unit: 'HOURS') {
         currentBuild.result = 'FAILURE'
         throw e
     } finally {
-        // jenkinsNotify()
+        jenkinsNotify()
     }
 }
 
@@ -133,7 +133,7 @@ def buildProcess(String stageKey, String jdkName, String jdkTestName, String mvn
         }
 
         def properties = ["-Djacoco.skip=${!makeReports}", "\"-Dmaven.repo.local=${mvnLocalRepoDir}\""]
-        println "Setting JDK for testing ${jdkName}"
+        println "Setting JDK for testing ${jdkTestName}"
         def cmd = ['mvn'] + goals + options + properties
 
         stage("build ${stageKey}") {
@@ -143,6 +143,7 @@ def buildProcess(String stageKey, String jdkName, String jdkTestName, String mvn
                          "MAVEN_OPTS=${mavenOpts}",
                          "PATH+MAVEN=${tool(mvnName)}/bin:${tool(jdkName)}/bin"
                 ]) {
+                    sh '$JAVA_HOME_IT/bin/java -version'
                     sh 'echo JAVA_HOME=$JAVA_HOME, JAVA_HOME_IT=$JAVA_HOME_IT, PATH=$PATH'
                     def script = cmd + ['\"-Djdk.home=$JAVA_HOME_IT\"']
                     def error = sh(returnStatus: true, script: script.join(' '))
@@ -154,6 +155,7 @@ def buildProcess(String stageKey, String jdkName, String jdkTestName, String mvn
                          "MAVEN_OPTS=${mavenOpts}",
                          "PATH+MAVEN=${tool(mvnName)}\\bin;${tool(jdkName)}\\bin"
                 ]) {
+                    bat '%JAVA_HOME_IT%\\bin\\java -version'
                     bat 'echo JAVA_HOME=%JAVA_HOME%, JAVA_HOME_IT=%JAVA_HOME_IT%, PATH=%PATH%'
                     def script = cmd + ['\"-Djdk.home=%JAVA_HOME_IT%\"']
                     def error = bat(returnStatus: true, script: script.join(' '))
@@ -205,6 +207,7 @@ static def sourcesPatternCsv() {
             '**/maven-surefire-report-plugin/src/main/java,' +
             '**/surefire-api/src/main/java,' +
             '**/surefire-booter/src/main/java,' +
+            '**/surefire-extensions-api/src/main/java,' +
             '**/surefire-grouper/src/main/java,' +
             '**/surefire-its/src/main/java,' +
             '**/surefire-logger-api/src/main/java,' +
@@ -220,6 +223,7 @@ static def classPatternCsv() {
             '**/maven-surefire-report-plugin/target/classes,' +
             '**/surefire-api/target/classes,' +
             '**/surefire-booter/target/classes,' +
+            '**/surefire-extensions-api/target/classes,' +
             '**/surefire-grouper/target/classes,' +
             '**/surefire-its/target/classes,' +
             '**/surefire-logger-api/target/classes,' +
diff --git a/maven-failsafe-plugin/pom.xml b/maven-failsafe-plugin/pom.xml
index bf61284..2e85275 100644
--- a/maven-failsafe-plugin/pom.xml
+++ b/maven-failsafe-plugin/pom.xml
@@ -341,7 +341,7 @@
                         <configuration>
                             <javaHome>${jdk.home}</javaHome>
                             <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
-                            <mavenOpts>-Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2</mavenOpts>
+                            <mavenOpts>-Dhttps.protocols=TLSv1.2 -Djdk.tls.client.protocols=TLSv1.2</mavenOpts>
                         </configuration>
                     </plugin>
                 </plugins>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index b4e303e..15b1dd0 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -207,8 +207,9 @@ public final class CommandReader
 
     public void stop()
     {
-        if ( state.compareAndSet( NEW, TERMINATED ) || state.compareAndSet( RUNNABLE, TERMINATED ) )
+        if ( !isStopped() )
         {
+            state.set( TERMINATED );
             makeQueueFull();
             listeners.clear();
             commandThread.interrupt();
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
index ebc1b27..2144e5a 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -30,6 +30,8 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import java.lang.reflect.InvocationTargetException;
 import java.security.AccessControlException;
 import java.security.AccessController;
@@ -47,6 +49,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.maven.surefire.booter.SystemPropertyManager.setSystemProperties;
 import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
 import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
+import static org.apache.maven.surefire.util.internal.StringUtils.NL;
 
 /**
  * The part of the booter that is unique to a forked vm.
@@ -62,12 +65,13 @@ public final class ForkedBooter
 {
     private static final long DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS = 30L;
     private static final long PING_TIMEOUT_IN_SECONDS = 30L;
-    private static final long ONE_SECOND_IN_MILLIS = 1000L;
+    private static final long ONE_SECOND_IN_MILLIS = 1_000L;
     private static final String LAST_DITCH_SHUTDOWN_THREAD = "surefire-forkedjvm-last-ditch-daemon-shutdown-thread-";
     private static final String PING_THREAD = "surefire-forkedjvm-ping-";
 
     private final CommandReader commandReader = CommandReader.getReader();
     private final ForkedChannelEncoder eventChannel = new ForkedChannelEncoder( System.out );
+    private final Semaphore exitBarrier = new Semaphore( 0 );
 
     private volatile long systemExitTimeoutInSeconds = DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS;
     private volatile PingScheduler pingScheduler;
@@ -83,7 +87,6 @@ public final class ForkedBooter
     {
         BooterDeserializer booterDeserializer =
                 new BooterDeserializer( createSurefirePropertiesIfFileExists( tmpDir, surefirePropsFileName ) );
-        // todo: print PID in debug console logger in version 2.21.2
         pingScheduler = isDebugging() ? null : listenToShutdownCommands( booterDeserializer.getPluginPid() );
         setSystemProperties( new File( tmpDir, effectiveSystemPropertiesFileName ) );
 
@@ -91,6 +94,12 @@ public final class ForkedBooter
         DumpErrorSingleton.getSingleton()
                 .init( providerConfiguration.getReporterConfiguration().getReportsDirectory(), dumpFileName );
 
+        if ( isDebugging() )
+        {
+            DumpErrorSingleton.getSingleton()
+                    .dumpText( "Found Maven process ID " + booterDeserializer.getPluginPid() );
+        }
+
         startupConfiguration = booterDeserializer.getProviderConfiguration();
         systemExitTimeoutInSeconds = providerConfiguration.systemExitTimeout( DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
 
@@ -118,18 +127,21 @@ public final class ForkedBooter
         {
             runSuitesInProcess();
         }
-        catch ( InvocationTargetException t )
+        catch ( InvocationTargetException e )
         {
-            Throwable e = t.getTargetException();
-            DumpErrorSingleton.getSingleton().dumpException( e );
-            eventChannel.consoleErrorLog( new LegacyPojoStackTraceWriter( "test subsystem", "no method", e ), false );
+            Throwable t = e.getTargetException();
+            DumpErrorSingleton.getSingleton().dumpException( t );
+            eventChannel.consoleErrorLog( new LegacyPojoStackTraceWriter( "test subsystem", "no method", t ), false );
         }
         catch ( Throwable t )
         {
             DumpErrorSingleton.getSingleton().dumpException( t );
             eventChannel.consoleErrorLog( new LegacyPojoStackTraceWriter( "test subsystem", "no method", t ), false );
         }
-        acknowledgedExit();
+        finally
+        {
+            acknowledgedExit();
+        }
     }
 
     private Object createTestSet( TypeEncodedValue forkedTestSet, boolean readTestsFromCommandReader, ClassLoader cl )
@@ -202,7 +214,11 @@ public final class ForkedBooter
                                  && !pingMechanism.pingScheduler.isShutdown() )
                     {
                         DumpErrorSingleton.getSingleton()
-                                .dumpText( "Killing self fork JVM. Maven process died." );
+                                .dumpText( "Killing self fork JVM. Maven process died."
+                                        + NL
+                                        + "Thread dump before killing the process (" + getProcessName() + "):"
+                                        + NL
+                                        + generateThreadDump() );
 
                         kill();
                     }
@@ -239,17 +255,33 @@ public final class ForkedBooter
                 if ( shutdown.isKill() )
                 {
                     DumpErrorSingleton.getSingleton()
-                            .dumpText( "Killing self fork JVM. Received SHUTDOWN command from Maven shutdown hook." );
+                            .dumpText( "Killing self fork JVM. Received SHUTDOWN command from Maven shutdown hook."
+                                    + NL
+                                    + "Thread dump before killing the process (" + getProcessName() + "):"
+                                    + NL
+                                    + generateThreadDump() );
                     kill();
                 }
                 else if ( shutdown.isExit() )
                 {
                     cancelPingScheduler();
                     DumpErrorSingleton.getSingleton()
-                            .dumpText( "Exiting self fork JVM. Received SHUTDOWN command from Maven shutdown hook." );
+                            .dumpText( "Exiting self fork JVM. Received SHUTDOWN command from Maven shutdown hook."
+                                    + NL
+                                    + "Thread dump before exiting the process (" + getProcessName() + "):"
+                                    + NL
+                                    + generateThreadDump() );
+                    exitBarrier.release();
                     exit1();
                 }
-                // else refers to shutdown=testset, but not used now, keeping reader open
+                else
+                {
+                    // else refers to shutdown=testset, but not used now, keeping reader open
+                    DumpErrorSingleton.getSingleton()
+                            .dumpText( "Thread dump for process (" + getProcessName() + "):"
+                                    + NL
+                                    + generateThreadDump() );
+                }
             }
         };
     }
@@ -267,7 +299,11 @@ public final class ForkedBooter
                     if ( !hasPing )
                     {
                         DumpErrorSingleton.getSingleton()
-                                .dumpText( "Killing self fork JVM. PING timeout elapsed." );
+                                .dumpText( "Killing self fork JVM. PING timeout elapsed."
+                                        + NL
+                                        + "Thread dump before killing the process (" + getProcessName() + "):"
+                                        + NL
+                                        + generateThreadDump() );
 
                         kill();
                     }
@@ -295,20 +331,19 @@ public final class ForkedBooter
 
     private void acknowledgedExit()
     {
-        final Semaphore barrier = new Semaphore( 0 );
         commandReader.addByeAckListener( new CommandListener()
                                           {
                                               @Override
                                               public void update( Command command )
                                               {
-                                                  barrier.release();
+                                                  exitBarrier.release();
                                               }
                                           }
         );
         eventChannel.bye();
         launchLastDitchDaemonShutdownThread( 0 );
         long timeoutMillis = max( systemExitTimeoutInSeconds * ONE_SECOND_IN_MILLIS, ONE_SECOND_IN_MILLIS );
-        acquireOnePermit( barrier, timeoutMillis );
+        acquireOnePermit( exitBarrier, timeoutMillis );
         cancelPingScheduler();
         commandReader.stop();
         System.exit( 0 );
@@ -342,14 +377,24 @@ public final class ForkedBooter
     @SuppressWarnings( "checkstyle:emptyblock" )
     private void launchLastDitchDaemonShutdownThread( final int returnCode )
     {
-        getJvmTerminator().schedule( new Runnable()
-                                        {
-                                            @Override
-                                            public void run()
-                                            {
-                                                kill( returnCode );
-                                            }
-                                        }, systemExitTimeoutInSeconds, SECONDS
+        getJvmTerminator()
+                .schedule( new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        DumpErrorSingleton.getSingleton()
+                                .dumpText( "Thread dump for process ("
+                                        + getProcessName()
+                                        + ") after "
+                                        + systemExitTimeoutInSeconds
+                                        + " seconds shutdown timeout:"
+                                        + NL
+                                        + generateThreadDump() );
+
+                        kill( returnCode );
+                    }
+                }, systemExitTimeoutInSeconds, SECONDS
         );
     }
 
@@ -385,9 +430,20 @@ public final class ForkedBooter
      *
      * @param args Commandline arguments
      */
-    public static void main( String... args )
+    public static void main( String[] args )
     {
         ForkedBooter booter = new ForkedBooter();
+        run( booter, args );
+    }
+
+    /**
+     * created for testing purposes.
+     *
+     * @param booter booter in JVM
+     * @param args arguments passed to JVM
+     */
+    private static void run( ForkedBooter booter, String[] args )
+    {
         try
         {
             booter.setupBooter( args[0], args[1], args[2], args.length > 3 ? args[3] : null );
@@ -472,4 +528,34 @@ public final class ForkedBooter
             return pingScheduler.isShutdown();
         }
     }
+
+    private static String generateThreadDump()
+    {
+        StringBuilder dump = new StringBuilder();
+        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+        ThreadInfo[] threadInfos = threadMXBean.getThreadInfo( threadMXBean.getAllThreadIds(), 100 );
+        for ( ThreadInfo threadInfo : threadInfos )
+        {
+            dump.append( '"' );
+            dump.append( threadInfo.getThreadName() );
+            dump.append( "\" " );
+            Thread.State state = threadInfo.getThreadState();
+            dump.append( "\n   java.lang.Thread.State: " );
+            dump.append( state );
+            StackTraceElement[] stackTraceElements = threadInfo.getStackTrace();
+            for ( StackTraceElement stackTraceElement : stackTraceElements )
+            {
+                dump.append( "\n        at " );
+                dump.append( stackTraceElement );
+            }
+            dump.append( "\n\n" );
+        }
+        return dump.toString();
+    }
+
+    private static String getProcessName()
+    {
+        return ManagementFactory.getRuntimeMXBean()
+                .getName();
+    }
 }
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
new file mode 100644
index 0000000..e65beb1
--- /dev/null
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
@@ -0,0 +1,134 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.times;
+import static org.powermock.api.mockito.PowerMockito.doCallRealMethod;
+import static org.powermock.api.mockito.PowerMockito.doThrow;
+import static org.powermock.api.mockito.PowerMockito.verifyNoMoreInteractions;
+import static org.powermock.api.mockito.PowerMockito.verifyPrivate;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ * PowerMock tests for {@link ForkedBooter}.
+ */
+@RunWith( PowerMockRunner.class )
+@PrepareForTest( { PpidChecker.class, ForkedBooter.class } )
+public class ForkedBooterMockTest
+{
+    @Mock
+    private PpidChecker pluginProcessChecker;
+
+    @Mock
+    private ForkedBooter booter;
+
+    @Test
+    public void shouldCheckNewPingMechanism() throws Exception
+    {
+        boolean canUse = invokeMethod( ForkedBooter.class, "canUseNewPingMechanism", (PpidChecker) null );
+        assertThat( canUse ).isFalse();
+
+        when( pluginProcessChecker.canUse() ).thenReturn( false );
+        canUse = invokeMethod( ForkedBooter.class, "canUseNewPingMechanism", pluginProcessChecker );
+        assertThat( canUse ).isFalse();
+
+        when( pluginProcessChecker.canUse() ).thenReturn( true );
+        canUse = invokeMethod( ForkedBooter.class, "canUseNewPingMechanism", pluginProcessChecker );
+        assertThat( canUse ).isTrue();
+    }
+
+    @Test
+    public void testMain() throws Exception
+    {
+        PowerMockito.mockStatic( ForkedBooter.class );
+
+        ArgumentCaptor<String[]> capturedArgs = ArgumentCaptor.forClass( String[].class );
+        ArgumentCaptor<ForkedBooter> capturedBooter = ArgumentCaptor.forClass( ForkedBooter.class );
+        doCallRealMethod()
+                .when( ForkedBooter.class, "run", capturedBooter.capture(), capturedArgs.capture() );
+
+        String[] args = new String[]{ "/", "dump", "surefire.properties", "surefire-effective.properties" };
+        invokeMethod( ForkedBooter.class, "run", booter, args );
+
+        assertThat( capturedBooter.getAllValues() )
+                .hasSize( 1 )
+                .contains( booter );
+
+        assertThat( capturedArgs.getAllValues() )
+                .hasSize( 1 );
+        assertThat( capturedArgs.getAllValues().get( 0 )[0] )
+                .isEqualTo( "/" );
+        assertThat( capturedArgs.getAllValues().get( 0 )[1] )
+                .isEqualTo( "dump" );
+        assertThat( capturedArgs.getAllValues().get( 0 )[2] )
+                .isEqualTo( "surefire.properties" );
+        assertThat( capturedArgs.getAllValues().get( 0 )[3] )
+                .isEqualTo( "surefire-effective.properties" );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "setupBooter", same( args[0] ), same( args[1] ), same( args[2] ), same( args[3] ) );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "execute" );
+
+        verifyNoMoreInteractions( booter );
+    }
+
+    @Test
+    public void testMainWithError() throws Exception
+    {
+        PowerMockito.mockStatic( ForkedBooter.class );
+
+        doCallRealMethod()
+                .when( ForkedBooter.class, "run", any( ForkedBooter.class ), any( String[].class ) );
+
+        doThrow( new RuntimeException( "dummy exception" ) )
+                .when( booter, "execute" );
+
+        String[] args = new String[]{ "/", "dump", "surefire.properties", "surefire-effective.properties" };
+        invokeMethod( ForkedBooter.class, "run", booter, args );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "setupBooter", same( args[0] ), same( args[1] ), same( args[2] ), same( args[3] ) );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "execute" );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "cancelPingScheduler" );
+
+        verifyPrivate( booter, times( 1 ) )
+                .invoke( "exit1" );
+
+        verifyNoMoreInteractions( booter );
+    }
+}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
new file mode 100644
index 0000000..42feda6
--- /dev/null
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
@@ -0,0 +1,144 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * 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.commons.io.FileUtils;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.ScheduledExecutorService;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ * Tests for {@link ForkedBooter}.
+ */
+public class ForkedBooterTest
+{
+    @Test
+    public void shouldGenerateThreadDump() throws Exception
+    {
+        Collection<String> threadNames = new ArrayList<>();
+        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+        for ( ThreadInfo threadInfo : threadMXBean.getThreadInfo( threadMXBean.getAllThreadIds(), 100 ) )
+        {
+            threadNames.add( threadInfo.getThreadName() );
+        }
+
+        String dump = invokeMethod( ForkedBooter.class, "generateThreadDump" );
+
+        for ( String threadName : threadNames )
+        {
+            assertThat( dump )
+                    .contains( "\"" + threadName + "\"" );
+        }
+
+        assertThat( dump )
+                .contains( "   java.lang.Thread.State: " )
+                .contains( "        at " );
+    }
+
+    @Test
+    public void shouldFindCurrentProcessName() throws Exception
+    {
+        String process = ManagementFactory.getRuntimeMXBean().getName();
+        String expected = invokeMethod( ForkedBooter.class, "getProcessName" );
+        assertThat( process ).isEqualTo( expected );
+    }
+
+    @Test
+    public void shouldNotBeDebugMode() throws Exception
+    {
+        boolean expected = invokeMethod( ForkedBooter.class, "isDebugging" );
+        assertThat( expected ).isFalse();
+    }
+
+    @Test
+    public void shouldReadSurefireProperties() throws Exception
+    {
+        File target = new File( System.getProperty( "user.dir", "target" ) );
+        File tmpDir = new File( target, "ForkedBooterTest.1" );
+        assertThat( tmpDir.mkdirs() )
+                .isTrue();
+
+        try
+        {
+            try ( InputStream is = invokeMethod( ForkedBooter.class, "createSurefirePropertiesIfFileExists",
+                    tmpDir.getCanonicalPath(), "surefire.properties" ) )
+            {
+                assertThat( is )
+                        .isNull();
+            }
+
+            File props = new File( tmpDir, "surefire.properties" );
+
+            assertThat( props.createNewFile() )
+                    .isTrue();
+
+            FileUtils.write( props, "key=value", UTF_8 );
+
+            try ( InputStream is2 = invokeMethod( ForkedBooter.class, "createSurefirePropertiesIfFileExists",
+                    tmpDir.getCanonicalPath(), "surefire.properties" ) )
+            {
+                assertThat( is2 )
+                        .isNotNull()
+                        .isInstanceOf( FileInputStream.class );
+
+                byte[] propsContent = new byte[20];
+                int length = is2.read( propsContent );
+
+                assertThat( new String( propsContent, 0, length ) )
+                        .isEqualTo( "key=value" );
+            }
+        }
+        finally
+        {
+            FileUtils.deleteDirectory( tmpDir );
+        }
+    }
+
+    @Test
+    public void shouldCreateScheduler() throws Exception
+    {
+        ScheduledExecutorService scheduler = null;
+        try
+        {
+            scheduler = invokeMethod( ForkedBooter.class, "createPingScheduler" );
+            assertThat( scheduler )
+                    .isNotNull();
+        }
+        finally
+        {
+            if ( scheduler != null )
+            {
+                scheduler.shutdownNow();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
index ff731c4..1fc9de6 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
@@ -37,6 +37,8 @@ public class JUnit4SuiteTest extends TestCase
         TestSuite suite = new TestSuite();
         suite.addTest( new JUnit4TestAdapter( PpidCheckerTest.class ) );
         suite.addTest( new JUnit4TestAdapter( SystemUtilsTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( ForkedBooterTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( ForkedBooterMockTest.class ) );
         suite.addTestSuite( ClasspathTest.class );
         suite.addTestSuite( PropertiesWrapperTest.class );
         return suite;
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
index a5740c0..e1d09ba 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
@@ -19,48 +19,118 @@ package org.apache.maven.surefire.its.jiras;
  * under the License.
  */
 
+import com.googlecode.junittoolbox.ParallelParameterized;
 import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.w3c.dom.Document;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
+import java.io.File;
+import java.util.ArrayList;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+@RunWith( ParallelParameterized.class )
 public class Surefire946KillMainProcessInReusableForkIT
     extends SurefireJUnit4IntegrationTestCase
 {
-    // there are 10 test classes that each would wait 2 seconds.
-    private static final int TEST_SLEEP_TIME = 2000;
+    private static final Object LOCK_DEPENDENCY = new Object();
+    private static final Object LOCK_PLUGIN = new Object();
 
-    @BeforeClass
-    public static void installSelfdestructPlugin()
-    {
-        unpack( Surefire946KillMainProcessInReusableForkIT.class, "surefire-946-self-destruct-plugin", "plugin" ).executeInstall();
-    }
+    // there are 10 test classes that each would wait 3.5 seconds.
+    private static final int TEST_SLEEP_TIME = 3_500;
+
+    private String classifierOfDummyDependency;
+
+    @Parameter
+    public String shutdownMavenMethod;
 
-    @Test( timeout = 30000 )
-    public void testHalt()
+    @Parameter( 1 )
+    public String shutdownSurefireMethod;
+
+    @Parameters( name = "{0}-{1}")
+    public static Iterable<Object[]> data()
     {
-        doTest( "halt" );
+        ArrayList<Object[]> args = new ArrayList<>();
+        args.add( new Object[] { "halt", "exit" } );
+        args.add( new Object[] { "halt", "kill" } );
+        args.add( new Object[] { "exit", "exit" } );
+        args.add( new Object[] { "exit", "kill" } );
+        args.add( new Object[] { "interrupt", "exit" } );
+        args.add( new Object[] { "interrupt", "kill" } );
+        return args;
     }
 
-    @Test( timeout = 30000 )
-    public void testExit()
+    @BeforeClass
+    public static void installSelfdestructPlugin()
     {
-        doTest( "exit" );
+        synchronized ( LOCK_PLUGIN )
+        {
+            unpack( Surefire946KillMainProcessInReusableForkIT.class, "surefire-946-self-destruct-plugin", "plugin" )
+                    .executeInstall();
+        }
     }
 
-    @Test( timeout = 30000 )
-    public void testInterrupt()
+    @Before
+    public void dummyDep()
     {
-        doTest( "interrupt" );
+        synchronized ( LOCK_DEPENDENCY )
+        {
+            classifierOfDummyDependency = shutdownMavenMethod + shutdownSurefireMethod;
+            unpack( Surefire946KillMainProcessInReusableForkIT.class,
+                    "surefire-946-dummy-dependency", classifierOfDummyDependency )
+                    .sysProp( "distinct.classifier", classifierOfDummyDependency )
+                    .executeInstall();
+        }
     }
 
-    private void doTest( String method )
+    @Test( timeout = 60_000 )
+    public void test() throws Exception
     {
-        unpack( "surefire-946-killMainProcessInReusableFork" )
-            .sysProp( "selfdestruct.timeoutInMillis", "5000" )
-            .sysProp( "selfdestruct.method", method )
-            .sysProp( "testSleepTime", String.valueOf( TEST_SLEEP_TIME ) )
-            .addGoal( "org.apache.maven.plugins.surefire:maven-selfdestruct-plugin:selfdestruct" )
-            .setForkJvm()
-            .forkPerThread().threadCount( 1 ).reuseForks( true ).maven().withFailure().executeTest();
+        unpack( "surefire-946-killMainProcessInReusableFork",
+                "-" + shutdownMavenMethod + "-" + shutdownSurefireMethod )
+                .sysProp( "distinct.classifier", classifierOfDummyDependency )
+                .sysProp( "surefire.shutdown", shutdownSurefireMethod )
+                .sysProp( "selfdestruct.timeoutInMillis", "5000" )
+                .sysProp( "selfdestruct.method", shutdownMavenMethod )
+                .sysProp( "testSleepTime", String.valueOf( TEST_SLEEP_TIME ) )
+                .addGoal( "org.apache.maven.plugins.surefire:maven-selfdestruct-plugin:selfdestruct" )
+                .setForkJvm()
+                .forkPerThread().threadCount( 1 ).reuseForks( true ).maven().withFailure().executeTest();
+
+
+        XPathFactory xpathFactory = XPathFactory.newInstance();
+        XPath xpath = xpathFactory.newXPath();
+        File settings = new File( System.getProperty( "maven.settings.file" ) ).getCanonicalFile();
+        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( settings );
+        String localRepository = xpath.evaluate( "/settings/localRepository", doc );
+        assertThat( localRepository )
+                .isNotNull()
+                .isNotEmpty();
+
+        File dep = new File( localRepository,
+                "org/apache/maven/plugins/surefire/surefire-946-dummy-dependency/0.1/"
+                        + "surefire-946-dummy-dependency-0.1-" + classifierOfDummyDependency + ".jar" );
+
+        assertThat( dep )
+                .exists();
+
+        boolean deleted;
+        int iterations = 0;
+        do
+        {
+            Thread.sleep( 1_000L );
+            deleted = dep.delete();
+        }
+        while ( !deleted && ++iterations < 10 );
+        assertThat( deleted )
+                .isTrue();
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-946-dummy-dependency/pom.xml b/surefire-its/src/test/resources/surefire-946-dummy-dependency/pom.xml
new file mode 100644
index 0000000..d2fdf86
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-946-dummy-dependency/pom.xml
@@ -0,0 +1,39 @@
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.maven.plugins.surefire</groupId>
+    <artifactId>surefire-946-dummy-dependency</artifactId>
+    <version>0.1</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.7</maven.compiler.source>
+        <maven.compiler.target>1.7</maven.compiler.target>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <!--
+                No test sources here.
+                Purpose to pre-install.
+                See the Surefire946KillMainProcessInReusableForkIT.
+                -->
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${surefire.version}</version>
+                <configuration>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.1.2</version>
+                <configuration>
+                    <classifier>${distinct.classifier}</classifier>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java b/surefire-its/src/test/resources/surefire-946-dummy-dependency/src/main/java/dummy/DummyClass.java
similarity index 67%
copy from surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
copy to surefire-its/src/test/resources/surefire-946-dummy-dependency/src/main/java/dummy/DummyClass.java
index 6d082cb..014cabb 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
+++ b/surefire-its/src/test/resources/surefire-946-dummy-dependency/src/main/java/dummy/DummyClass.java
@@ -1,5 +1,3 @@
-package junit44.environment;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,27 +17,16 @@ package junit44.environment;
  * under the License.
  */
 
-import org.junit.AfterClass;
-import org.junit.Test;
+package dummy;
 
-public class Basic04Test
+/**
+ *
+ */
+public class DummyClass
 {
-
-    @Test
-    public void testNothing()
+    @Override
+    public String toString()
     {
+        return "JVM handles a file handler to 'surefire-946-dummy-dependency-0.1.jar'.";
     }
-
-    @AfterClass
-    public static void waitSomeTimeAround()
-    {
-        try
-        {
-            Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
-        }
-        catch ( InterruptedException ignored )
-        {
-        }
-    }
-
-}
+}
\ No newline at end of file
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
index 53bb0a3..2240fe4 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
@@ -27,12 +27,19 @@
 	<name>Tests killing the main maven process when using reusable forks</name>
 
 	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<maven.compiler.source>1.7</maven.compiler.source>
 		<maven.compiler.target>1.7</maven.compiler.target>
 	</properties>
 
 	<dependencies>
 		<dependency>
+			<groupId>org.apache.maven.plugins.surefire</groupId>
+			<artifactId>surefire-946-dummy-dependency</artifactId>
+			<version>0.1</version>
+			<classifier>${distinct.classifier}</classifier>
+		</dependency>
+		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
 			<version>4.4</version>
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
index 8c52d1b..77971fd 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic01Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
index 6ef33f9..1133efe 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic02Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
index b1d7c71..15b1bd9 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic03Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
index 6d082cb..4151336 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic04Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
index 92f5f15..3f14261 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic05Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
index 2a44568..1925665 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic06Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
index 64f180e..77436bb 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic07Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
index 5a4c382..ed62c32 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic08Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
index 2461d11..87043e2 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic09Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
index 1e57b13..d481da7 100644
--- a/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
+++ b/surefire-its/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
@@ -19,6 +19,7 @@ package junit44.environment;
  * under the License.
  */
 
+import dummy.DummyClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
@@ -28,6 +29,7 @@ public class Basic10Test
     @Test
     public void testNothing()
     {
+        System.out.println( new DummyClass().toString() );
     }
 
     @AfterClass
diff --git a/surefire-its/src/test/resources/surefire-946-self-destruct-plugin/pom.xml b/surefire-its/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
index ad4ff00..5abb052 100644
--- a/surefire-its/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
+++ b/surefire-its/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
@@ -22,12 +22,6 @@
       <artifactId>maven-plugin-api</artifactId>
       <version>2.0</version>
     </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>3.8.1</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <build>