[SUREFIRE-1181] "forkedProcessTimeoutInSeconds" does not kill forked JVM 
although interrupted build


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

Branch: refs/heads/master
Commit: 9b5752f99be3408ff64f608ccce1373e69d1f010
Parents: 225e3cb
Author: tibordigana <tibo...@lycos.com>
Authored: Sun Oct 4 21:40:39 2015 +0200
Committer: tibordigana <tibo...@lycos.com>
Committed: Sun Oct 4 21:40:39 2015 +0200

----------------------------------------------------------------------
 .../surefire/booterclient/ForkStarter.java      | 67 ++++++++++++++-----
 .../booterclient/output/ForkClient.java         | 69 +++++++++++++++-----
 .../booterclient/ForkingRunListenerTest.java    | 19 ++++--
 .../booterclient/MockNotifiableTestStream.java  | 49 ++++++++++++++
 .../surefire/booter/MasterProcessCommand.java   | 10 ++-
 .../booter/MasterProcessCommandTest.java        |  3 +-
 .../maven/surefire/booter/ForkedBooter.java     | 32 +++++----
 7 files changed, 195 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index 4742b7c..6f9624c 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -31,8 +31,8 @@ import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvid
 import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
 import 
org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
+import org.apache.maven.shared.utils.cli.CommandLineCallable;
 import org.apache.maven.shared.utils.cli.CommandLineException;
-import org.apache.maven.shared.utils.cli.CommandLineTimeOutException;
 import org.apache.maven.surefire.booter.Classpath;
 import org.apache.maven.surefire.booter.ClasspathConfiguration;
 import org.apache.maven.surefire.booter.KeyValueSource;
@@ -74,8 +74,9 @@ import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
-import static 
org.apache.maven.shared.utils.cli.CommandLineUtils.executeCommandLine;
+import static 
org.apache.maven.shared.utils.cli.CommandLineUtils.executeCommandLineAsCallable;
 import static 
org.apache.maven.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
 import static 
org.apache.maven.shared.utils.cli.ShutdownHookUtils.removeShutdownHook;
 import static 
org.apache.maven.surefire.util.internal.StringUtils.FORK_STREAM_CHARSET_NAME;
@@ -110,6 +111,8 @@ public class ForkStarter
 {
     private static final long PING_IN_SECONDS = 10;
 
+    private static final int TIMEOUT_CHECK_PERIOD_MILLIS = 100;
+
     private static final ThreadFactory FORKED_JVM_DAEMON_THREAD_FACTORY
         = newDaemonThreadFactory( "surefire-fork-starter" );
 
@@ -118,6 +121,10 @@ public class ForkStarter
 
     private final ScheduledExecutorService pingThreadScheduler = 
createPingScheduler();
 
+    private final ScheduledExecutorService timeoutCheckScheduler;
+
+    private final Queue<ForkClient> currentForkClients;
+
     /**
      * Closes an InputStream
      */
@@ -179,6 +186,9 @@ public class ForkStarter
         defaultReporterFactory = new DefaultReporterFactory( 
startupReportConfiguration );
         defaultReporterFactory.runStarting();
         defaultReporterFactories = new 
ConcurrentLinkedQueue<DefaultReporterFactory>();
+        currentForkClients = new ConcurrentLinkedQueue<ForkClient>();
+        timeoutCheckScheduler = createTimeoutCheckScheduler();
+        triggerTimeoutCheck();
     }
 
     public RunResult run( SurefireProperties effectiveSystemProperties, 
DefaultScanResult scanResult )
@@ -197,6 +207,7 @@ public class ForkStarter
             defaultReporterFactory.mergeFromOtherFactories( 
defaultReporterFactories );
             defaultReporterFactory.close();
             pingThreadScheduler.shutdownNow();
+            timeoutCheckScheduler.shutdownNow();
         }
     }
 
@@ -205,11 +216,11 @@ public class ForkStarter
     {
         DefaultReporterFactory forkedReporterFactory = new 
DefaultReporterFactory( startupReportConfiguration );
         defaultReporterFactories.add( forkedReporterFactory );
-        PropertiesWrapper props = new PropertiesWrapper( providerProperties );
-        ForkClient forkClient =
-            new ForkClient( forkedReporterFactory, 
startupReportConfiguration.getTestVmSystemProperties() );
         TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+        PropertiesWrapper props = new PropertiesWrapper( providerProperties );
         TestLessInputStream stream = builder.build();
+        ForkClient forkClient =
+            new ForkClient( forkedReporterFactory, 
startupReportConfiguration.getTestVmSystemProperties(), stream );
         Thread shutdown = createImmediateShutdownHookThread( builder, 
providerConfiguration.getShutdown() );
         ScheduledFuture<?> ping = triggerPingTimerForShutdown( builder );
         try
@@ -351,7 +362,8 @@ public class ForkStarter
                             new DefaultReporterFactory( 
startupReportConfiguration );
                         defaultReporterFactories.add( forkedReporterFactory );
                         Properties vmProps = 
startupReportConfiguration.getTestVmSystemProperties();
-                        ForkClient forkClient = new ForkClient( 
forkedReporterFactory, vmProps )
+                        ForkClient forkClient = new ForkClient( 
forkedReporterFactory, vmProps,
+                                                                
builder.getImmediateCommands() )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -529,21 +541,24 @@ public class ForkStarter
 
         try
         {
-            final int timeout = forkedProcessTimeoutInSeconds > 0 ? 
forkedProcessTimeoutInSeconds : 0;
+            CommandLineCallable future =
+                executeCommandLineAsCallable( cli, testProvidingInputStream, 
threadedStreamConsumer,
+                                              threadedStreamConsumer, 0, 
inputStreamCloser,
+                                              Charset.forName( 
FORK_STREAM_CHARSET_NAME ) );
 
-            final int result = executeCommandLine( cli, 
testProvidingInputStream, threadedStreamConsumer,
-                                                   threadedStreamConsumer, 
timeout, inputStreamCloser,
-                                                   Charset.forName( 
FORK_STREAM_CHARSET_NAME ) );
+            currentForkClients.add( forkClient );
 
-            if ( result != SUCCESS )
+            int result = future.call();
+
+            if ( forkClient.hadTimeout() )
+            {
+                runResult = timeout( 
forkClient.getDefaultReporterFactory().getGlobalRunStatistics().getRunResult() 
);
+            }
+            else if ( result != SUCCESS )
             {
                 throw new SurefireBooterForkException( "Error occurred in 
starting fork, check output in log" );
             }
         }
-        catch ( CommandLineTimeOutException e )
-        {
-            runResult = timeout( 
forkClient.getDefaultReporterFactory().getGlobalRunStatistics().getRunResult() 
);
-        }
         catch ( CommandLineException e )
         {
             runResult = failure( 
forkClient.getDefaultReporterFactory().getGlobalRunStatistics().getRunResult(), 
e );
@@ -551,6 +566,7 @@ public class ForkStarter
         }
         finally
         {
+            currentForkClients.remove( forkClient );
             threadedStreamConsumer.close();
             inputStreamCloser.run();
             removeShutdownHook( inputStreamCloserHook );
@@ -650,6 +666,12 @@ public class ForkStarter
         return Executors.newScheduledThreadPool( 1, threadFactory );
     }
 
+    private static ScheduledExecutorService createTimeoutCheckScheduler()
+    {
+        ThreadFactory threadFactory = newDaemonThreadFactory( 
"timeout-check-timer" );
+        return Executors.newScheduledThreadPool( 1, threadFactory );
+    }
+
     private ScheduledFuture<?> triggerPingTimerForShutdown( final 
TestLessInputStreamBuilder builder )
     {
         return pingThreadScheduler.scheduleAtFixedRate( new Runnable()
@@ -674,4 +696,19 @@ public class ForkStarter
             }
         }, 0, PING_IN_SECONDS, SECONDS );
     }
+
+    private ScheduledFuture<?> triggerTimeoutCheck()
+    {
+        return pingThreadScheduler.scheduleAtFixedRate( new Runnable()
+        {
+            public void run()
+            {
+                long systemTime = System.currentTimeMillis();
+                for ( ForkClient forkClient : currentForkClients )
+                {
+                    forkClient.tryToTimeout( systemTime, 
forkedProcessTimeoutInSeconds );
+                }
+            }
+        }, 0, TIMEOUT_CHECK_PERIOD_MILLIS, MILLISECONDS );
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
index 6cbc9bc..4d01b1a 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -28,6 +28,7 @@ import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
 
 import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
@@ -42,6 +43,8 @@ import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
 import org.apache.maven.surefire.util.internal.StringUtils;
 
+import static org.apache.maven.surefire.booter.Shutdown.KILL;
+
 /**
  * Knows how to reconstruct *all* the state transmitted over stdout by the 
forked process.
  *
@@ -50,6 +53,9 @@ import org.apache.maven.surefire.util.internal.StringUtils;
 public class ForkClient
     implements StreamConsumer
 {
+    private static final long START_TIME_ZERO = 0L;
+    private static final long START_TIME_NEGATIVE_TIMEOUT = -1L;
+
     private final DefaultReporterFactory defaultReporterFactory;
 
     private final NotifiableTestStream notifiableTestStream;
@@ -58,15 +64,16 @@ public class ForkClient
 
     private final Properties testVmSystemProperties;
 
+    /**
+     * <t>testSetStartedAt</t> is set to non-zero after received
+     * {@link ForkingRunListener#BOOTERCODE_TESTSET_STARTING test-set}.
+     */
+    private final AtomicLong testSetStartedAt = new AtomicLong( 
START_TIME_ZERO );
+
     private volatile boolean saidGoodBye;
 
     private volatile StackTraceWriter errorInFork;
 
-    public ForkClient( DefaultReporterFactory defaultReporterFactory, 
Properties testVmSystemProperties )
-    {
-        this( defaultReporterFactory, testVmSystemProperties, null );
-    }
-
     public ForkClient( DefaultReporterFactory defaultReporterFactory, 
Properties testVmSystemProperties,
                        NotifiableTestStream notifiableTestStream )
     {
@@ -79,12 +86,29 @@ public class ForkClient
     {
     }
 
-    public DefaultReporterFactory getDefaultReporterFactory()
+    /**
+     * Called in concurrent Thread.
+     */
+    public final void tryToTimeout( long currentTimeMillis, int 
forkedProcessTimeoutInSeconds )
+    {
+        if ( forkedProcessTimeoutInSeconds > 0 )
+        {
+            final long forkedProcessTimeoutInMillis = 1000 * 
forkedProcessTimeoutInSeconds;
+            final long startedAt = testSetStartedAt.get();
+            if ( startedAt > START_TIME_ZERO && currentTimeMillis - startedAt 
>= forkedProcessTimeoutInMillis )
+            {
+                testSetStartedAt.set( START_TIME_NEGATIVE_TIMEOUT );
+                notifiableTestStream.shutdown( KILL );
+            }
+        }
+    }
+
+    public final DefaultReporterFactory getDefaultReporterFactory()
     {
         return defaultReporterFactory;
     }
 
-    public void consumeLine( String s )
+    public final void consumeLine( String s )
     {
         if ( StringUtils.isNotBlank( s ) )
         {
@@ -92,6 +116,21 @@ public class ForkClient
         }
     }
 
+    private void setCurrentStartTime()
+    {
+        if ( testSetStartedAt.get() == START_TIME_ZERO ) // JIT can optimize 
<= no JNI call
+        {
+            // Not necessary to call JNI library library #currentTimeMillis
+            // which may waste 10 - 30 machine cycles in callback. Callbacks 
should be fast.
+            testSetStartedAt.compareAndSet( START_TIME_ZERO, 
System.currentTimeMillis() );
+        }
+    }
+
+    public final boolean hadTimeout()
+    {
+        return testSetStartedAt.get() == START_TIME_NEGATIVE_TIMEOUT;
+    }
+
     private void processLine( String s )
     {
         try
@@ -111,6 +150,7 @@ public class ForkClient
             {
                 case ForkingRunListener.BOOTERCODE_TESTSET_STARTING:
                     getOrCreateReporter( channelNumber ).testSetStarting( 
createReportEntry( remaining ) );
+                    setCurrentStartTime();
                     break;
                 case ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED:
                     getOrCreateReporter( channelNumber ).testSetCompleted( 
createReportEntry( remaining ) );
@@ -155,10 +195,7 @@ public class ForkClient
                     getOrCreateConsoleLogger( channelNumber ).info( 
createConsoleMessage( remaining ) );
                     break;
                 case ForkingRunListener.BOOTERCODE_NEXT_TEST:
-                    if ( notifiableTestStream != null )
-                    {
-                        notifiableTestStream.provideNewTest();
-                    }
+                    notifiableTestStream.provideNewTest();
                     break;
                 case ForkingRunListener.BOOTERCODE_ERROR:
                     errorInFork = deserializeStackTraceWriter( new 
StringTokenizer( remaining, "," ) );
@@ -213,7 +250,7 @@ public class ForkClient
         }
     }
 
-    public void consumeMultiLineContent( String s )
+    public final void consumeMultiLineContent( String s )
         throws IOException
     {
         BufferedReader stringReader = new BufferedReader( new StringReader( s 
) );
@@ -280,7 +317,7 @@ public class ForkClient
      * @param channelNumber The logical channel number
      * @return A mock provider reporter
      */
-    public RunListener getReporter( int channelNumber )
+    public final RunListener getReporter( int channelNumber )
     {
         return testSetReporters.get( channelNumber );
     }
@@ -310,17 +347,17 @@ public class ForkClient
     {
     }
 
-    public boolean isSaidGoodBye()
+    public final boolean isSaidGoodBye()
     {
         return saidGoodBye;
     }
 
-    public StackTraceWriter getErrorInFork()
+    public final StackTraceWriter getErrorInFork()
     {
         return errorInFork;
     }
 
-    public boolean isErrorInFork()
+    public final boolean isErrorInFork()
     {
         return errorInFork != null;
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
index 31e511c..63d3417 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
@@ -42,6 +42,10 @@ import org.apache.maven.surefire.report.StackTraceWriter;
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 /**
  * @author Kristian Rosenvold
  */
@@ -216,11 +220,12 @@ public class ForkingRunListenerTest
 
         TestSetMockReporterFactory providerReporterFactory = new 
TestSetMockReporterFactory();
         final Properties testVmSystemProperties = new Properties();
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, 
testVmSystemProperties );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, 
testVmSystemProperties,
+                                                      new 
MockNotifiableTestStream() );
 
         forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) 
);
 
-        assertTrue( testVmSystemProperties.size() > 1 );
+        assertThat( testVmSystemProperties.size(), is( greaterThan( 1 ) ) );
     }
 
     public void testMultipleEntries()
@@ -240,7 +245,8 @@ public class ForkingRunListenerTest
         forkingReporter.testSetCompleted( reportEntry );
 
         TestSetMockReporterFactory providerReporterFactory = new 
TestSetMockReporterFactory();
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, 
new Properties() );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, 
new Properties(),
+                                                      new 
MockNotifiableTestStream() );
 
         forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) 
);
 
@@ -263,7 +269,8 @@ public class ForkingRunListenerTest
         new ForkingRunListener( printStream, anotherChannel, false 
).testSkipped( secondExpected );
 
         TestSetMockReporterFactory providerReporterFactory = new 
TestSetMockReporterFactory();
-        final ForkClient forkStreamClient = new ForkClient( 
providerReporterFactory, new Properties() );
+        final ForkClient forkStreamClient = new ForkClient( 
providerReporterFactory, new Properties(),
+                                                            new 
MockNotifiableTestStream() );
         forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) 
);
 
         MockReporter reporter = (MockReporter) forkStreamClient.getReporter( 
defaultChannel );
@@ -337,12 +344,12 @@ public class ForkingRunListenerTest
             throws ReporterException, IOException
         {
             TestSetMockReporterFactory providerReporterFactory = new 
TestSetMockReporterFactory();
-            final ForkClient forkStreamClient = new ForkClient( 
providerReporterFactory, new Properties() );
+            final ForkClient forkStreamClient = new ForkClient( 
providerReporterFactory, new Properties(),
+                                                                new 
MockNotifiableTestStream() );
             forkStreamClient.consumeMultiLineContent( content.toString( ) );
             reporter = (MockReporter) forkStreamClient.getReporter( 
defaultChannel );
         }
 
-
         public String getFirstEvent()
         {
             return reporter.getEvents().get( 0 );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockNotifiableTestStream.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockNotifiableTestStream.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockNotifiableTestStream.java
new file mode 100644
index 0000000..12a5f92
--- /dev/null
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockNotifiableTestStream.java
@@ -0,0 +1,49 @@
+package org.apache.maven.plugin.surefire.booterclient;
+
+/*
+ * 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.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
+import org.apache.maven.surefire.booter.*;
+
+/**
+ * Mock of {@link NotifiableTestStream} for testing purposes.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.19
+ */
+final class MockNotifiableTestStream
+    implements NotifiableTestStream
+{
+    public void provideNewTest()
+    {
+    }
+
+    public void skipSinceNextTest()
+    {
+    }
+
+    public void shutdown( Shutdown shutdownType )
+    {
+    }
+
+    public void noop()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
 
b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
index 8059537..5e6bca9 100644
--- 
a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
+++ 
b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
@@ -44,7 +44,7 @@ public enum MasterProcessCommand
     RUN_CLASS( 0, String.class ),
     TEST_SET_FINISHED( 1, Void.class ),
     SKIP_SINCE_NEXT_TEST( 2, Void.class ),
-    SHUTDOWN( 3, Shutdown.class ),
+    SHUTDOWN( 3, String.class ),
 
     /** To tell a forked process that the master process is still alive. 
Repeated after 10 seconds. */
     NOOP( 4, Void.class );
@@ -79,10 +79,16 @@ public enum MasterProcessCommand
     @SuppressWarnings( "checkstyle:magicnumber" )
     public byte[] encode( String data )
     {
+        if ( !hasDataType() )
+        {
+            throw new IllegalArgumentException( "cannot use data without data 
type" );
+        }
+
         if ( getDataType() != String.class )
         {
-            throw new IllegalArgumentException( "Data type can be only " + 
getDataType() );
+            throw new IllegalArgumentException( "Data type can be only " + 
String.class );
         }
+
         byte[] dataBytes = fromDataType( data );
         byte[] encoded = new byte[8 + dataBytes.length];
         int command = getId();

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
 
b/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
index f7f7767..8396d8b 100644
--- 
a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
+++ 
b/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
@@ -29,7 +29,6 @@ import java.io.IOException;
 import static org.apache.maven.surefire.booter.MasterProcessCommand.*;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.assertNotNull;
 
 /**
  * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
@@ -105,7 +104,7 @@ public class MasterProcessCommandTest
                     assertNull( decoded );
                     break;
                 case SHUTDOWN:
-                    assertEquals( Shutdown.class, command.getDataType() );
+                    assertEquals( String.class, command.getDataType() );
                     encoded = command.fromDataType( Shutdown.EXIT.name() );
                     assertThat( encoded.length, is( 4 ) );
                     decoded = command.toDataTypeAsString( encoded );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/9b5752f9/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
----------------------------------------------------------------------
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 c7376f7..050da57 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
@@ -73,7 +73,8 @@ public final class ForkedBooter
      */
     public static void main( String... args )
     {
-        ScheduledFuture<?> pingScheduler = listenToShutdownCommands();
+        final MasterProcessReader reader = startupMasterProcessReader();
+        final ScheduledFuture<?> pingScheduler = listenToShutdownCommands( 
reader );
         final PrintStream originalOut = System.out;
         try
         {
@@ -138,7 +139,7 @@ public final class ForkedBooter
             encodeAndWriteToOutput( ( (char) BOOTERCODE_BYE ) + ",0,BYE!\n", 
originalOut );
             originalOut.flush();
             // noinspection CallToSystemExit
-            exit( 0, DEFAULT );
+            exit( 0, DEFAULT, reader );
         }
         catch ( Throwable t )
         {
@@ -146,7 +147,7 @@ public final class ForkedBooter
             // noinspection UseOfSystemOutOrSystemErr
             t.printStackTrace( System.err );
             // noinspection ProhibitedExceptionThrown,CallToSystemExit
-            exit( 1, DEFAULT );
+            exit( 1, DEFAULT, reader );
         }
         finally
         {
@@ -154,13 +155,18 @@ public final class ForkedBooter
         }
     }
 
-    private static ScheduledFuture<?> listenToShutdownCommands()
+    private static MasterProcessReader startupMasterProcessReader()
     {
-        MasterProcessReader reader = MasterProcessReader.getReader();
-        reader.addShutdownListener( createExitHandler() );
+        return MasterProcessReader.getReader();
+    }
+
+    private static ScheduledFuture<?> listenToShutdownCommands( 
MasterProcessReader reader )
+    {
+        reader.addShutdownListener( createExitHandler( reader ) );
         AtomicBoolean pingDone = new AtomicBoolean( true );
         reader.addNoopListener( createPingHandler( pingDone ) );
-        return JVM_TERMINATOR.scheduleAtFixedRate( createPingJob( pingDone ), 
0, PING_TIMEOUT_IN_SECONDS, SECONDS );
+        return JVM_TERMINATOR.scheduleAtFixedRate( createPingJob( pingDone, 
reader ),
+                                                   0, PING_TIMEOUT_IN_SECONDS, 
SECONDS );
     }
 
     private static MasterProcessListener createPingHandler( final 
AtomicBoolean pingDone )
@@ -174,18 +180,18 @@ public final class ForkedBooter
         };
     }
 
-    private static MasterProcessListener createExitHandler()
+    private static MasterProcessListener createExitHandler( final 
MasterProcessReader reader )
     {
         return new MasterProcessListener()
         {
             public void update( Command command )
             {
-                exit( 1, command.toShutdownData() );
+                exit( 1, command.toShutdownData(), reader );
             }
         };
     }
 
-    private static Runnable createPingJob( final AtomicBoolean pingDone )
+    private static Runnable createPingJob( final AtomicBoolean pingDone, final 
MasterProcessReader reader  )
     {
         return new Runnable()
         {
@@ -194,7 +200,7 @@ public final class ForkedBooter
                 boolean hasPing = pingDone.getAndSet( false );
                 if ( !hasPing )
                 {
-                    exit( 1, KILL );
+                    exit( 1, KILL, reader );
                 }
             }
         };
@@ -206,9 +212,9 @@ public final class ForkedBooter
         out.write( encodeBytes, 0, encodeBytes.length );
     }
 
-    private static void exit( int returnCode, Shutdown shutdownType )
+    private static void exit( int returnCode, Shutdown shutdownType, 
MasterProcessReader reader )
     {
-        MasterProcessReader.getReader().stop();
+        reader.stop();
         switch ( shutdownType )
         {
             case KILL:

Reply via email to