Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1302_4 b2536b846 -> cb5abc50e (forced update)


SUREFIRE-1302_4


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

Branch: refs/heads/SUREFIRE-1302_4
Commit: cb5abc50e5b88f654087e16668fb50a9462178f7
Parents: 4de017b
Author: Tibor17 <tibordig...@apache.org>
Authored: Wed Jul 19 01:21:41 2017 +0200
Committer: Tibor17 <tibordig...@apache.org>
Committed: Wed Jul 19 02:13:33 2017 +0200

----------------------------------------------------------------------
 maven-failsafe-plugin/pom.xml                   |  17 -
 maven-surefire-common/pom.xml                   |  13 +-
 .../plugin/surefire/SurefireProperties.java     |   8 +
 .../surefire/booterclient/BooterSerializer.java |   6 +-
 .../surefire/booterclient/ForkStarter.java      |  70 +++-
 .../surefire/report/FileReporterUtils.java      |  11 +-
 ...erDeserializerProviderConfigurationTest.java |   3 +-
 ...terDeserializerStartupConfigurationTest.java |   3 +-
 .../surefire/booterclient/ForkStarterTest.java  |  83 +++++
 .../apache/maven/surefire/JUnit4SuiteTest.java  |   4 +-
 maven-surefire-plugin/pom.xml                   |  17 -
 .../src/site/apt/examples/shutdown.apt.vm       |  26 +-
 maven-surefire-report-plugin/pom.xml            |   4 -
 pom.xml                                         |  17 +-
 surefire-api/pom.xml                            |  10 +-
 .../maven/surefire/booter/CommandReader.java    |   4 +-
 .../maven/surefire/util/ReflectionUtils.java    |  49 ++-
 .../java/org/apache/maven/JUnit4SuiteTest.java  |   4 +-
 .../surefire/util/ReflectionUtilsTest.java      | 110 +++++++
 surefire-booter/pom.xml                         |  25 +-
 .../maven/surefire/booter/BooterConstants.java  |   1 +
 .../surefire/booter/BooterDeserializer.java     |   8 +
 .../maven/surefire/booter/ForkedBooter.java     |  74 ++++-
 .../maven/surefire/booter/PpidChecker.java      | 321 +++++++++++++++++++
 .../maven/surefire/booter/ProcessInfo.java      | 110 +++++++
 .../surefire/booter/PropertiesWrapper.java      |   6 +
 .../maven/surefire/booter/JUnit4SuiteTest.java  |   3 +-
 .../maven/surefire/booter/PpidCheckerTest.java  | 163 ++++++++++
 ...urefire1295AttributeJvmCrashesToTestsIT.java |   6 +-
 29 files changed, 1080 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-failsafe-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/pom.xml b/maven-failsafe-plugin/pom.xml
index f42e682..ec48929 100644
--- a/maven-failsafe-plugin/pom.xml
+++ b/maven-failsafe-plugin/pom.xml
@@ -45,27 +45,10 @@
 
   <dependencies>
     <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven.surefire</groupId>
       <artifactId>maven-surefire-common</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven.surefire</groupId>
-      <artifactId>surefire-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.shared</groupId>
-      <artifactId>maven-shared-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.plugin-tools</groupId>
-      <artifactId>maven-plugin-annotations</artifactId>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <version>${project.version}</version>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index 4064bc2..e81a8fd 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -36,6 +36,11 @@
     <maven>2.2.1</maven>
   </prerequisites>
 
+  <properties>
+    <!-- Override with Jigsaw JDK 9 -->
+    <test.jdk>${java.home}/../bin/java</test.jdk>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.maven</groupId>
@@ -44,7 +49,6 @@
     <dependency>
       <groupId>org.apache.maven.plugin-tools</groupId>
       <artifactId>maven-plugin-annotations</artifactId>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.surefire</groupId>
@@ -93,6 +97,7 @@
     <dependency>
       <groupId>com.google.code.findbugs</groupId>
       <artifactId>jsr305</artifactId>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.shared</groupId>
@@ -160,6 +165,7 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
+          <jvm>${test.jdk}</jvm>
           <redirectTestOutputToFile>true</redirectTestOutputToFile>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
@@ -192,6 +198,7 @@
                   <include>org.apache.maven.shared:maven-shared-utils</include>
                   
<include>org.apache.maven.shared:maven-common-artifact-filters</include>
                   <include>commons-io:commons-io</include>
+                  <include>org.apache.commons:commons-lang3</include>
                 </includes>
               </artifactSet>
               <relocations>
@@ -203,6 +210,10 @@
                   <pattern>org.apache.commons.io</pattern>
                   
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.io</shadedPattern>
                 </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.lang3</pattern>
+                  
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.lang3</shadedPattern>
+                </relocation>
               </relocations>
             </configuration>
           </execution>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireProperties.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireProperties.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireProperties.java
index 4b13898..3783376 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireProperties.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireProperties.java
@@ -196,6 +196,14 @@ public class SurefireProperties
         }
     }
 
+    public void setProperty( String key, Long value )
+    {
+        if ( value != null )
+        {
+            setProperty( key, value.toString() );
+        }
+    }
+
     public void addList( List<?> items, String propertyPrefix )
     {
         if ( items != null && !items.isEmpty() )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
index 0299525..591e89c 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
@@ -70,12 +70,14 @@ class BooterSerializer
      * Does not modify sourceProperties
      */
     File serialize( KeyValueSource sourceProperties, ProviderConfiguration 
booterConfiguration,
-                           StartupConfiguration providerConfiguration, Object 
testSet, boolean readTestsFromInStream )
+                    StartupConfiguration providerConfiguration, Object 
testSet, boolean readTestsFromInStream,
+                    Long pid )
         throws IOException
     {
-
         SurefireProperties properties = new SurefireProperties( 
sourceProperties );
 
+        properties.setProperty( PLUGIN_PID, pid );
+
         ClasspathConfiguration cp = 
providerConfiguration.getClasspathConfiguration();
         properties.setClasspath( ClasspathConfiguration.CLASSPATH, 
cp.getTestClasspath() );
         properties.setClasspath( ClasspathConfiguration.SUREFIRE_CLASSPATH, 
cp.getProviderClasspath() );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/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 a2a5095..acb5a72 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
@@ -54,6 +54,7 @@ import org.apache.maven.surefire.util.DefaultScanResult;
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
@@ -78,6 +79,9 @@ import static java.util.Collections.addAll;
 import static java.util.concurrent.Executors.newScheduledThreadPool;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
 import static 
org.apache.maven.plugin.surefire.AbstractSurefireMojo.createCopyAndReplaceForkNumPlaceholder;
 import static org.apache.maven.plugin.surefire.SurefireHelper.DUMP_FILE_PREFIX;
 import static 
org.apache.maven.plugin.surefire.booterclient.ForkNumberBucket.drawNumber;
@@ -92,6 +96,8 @@ import static 
org.apache.maven.surefire.booter.SystemPropertyManager.writeProper
 import static org.apache.maven.surefire.suite.RunResult.SUCCESS;
 import static org.apache.maven.surefire.suite.RunResult.failure;
 import static org.apache.maven.surefire.suite.RunResult.timeout;
+import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodChain;
+import static org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass;
 import static 
org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
 import static 
org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThread;
 import static 
org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
@@ -114,6 +120,8 @@ import static 
org.apache.maven.surefire.util.internal.StringUtils.ISO_8859_1;
  */
 public class ForkStarter
 {
+    private static final Long PID = pid();
+
     private static final String EXECUTION_EXCEPTION = "ExecutionException";
 
     private static final long PING_IN_SECONDS = 10;
@@ -550,7 +558,8 @@ public class ForkStarter
             BooterSerializer booterSerializer = new BooterSerializer( 
forkConfiguration );
 
             surefireProperties = booterSerializer.serialize( 
providerProperties, providerConfiguration,
-                                                             
startupConfiguration, testSet, readTestsFromInStream );
+                                                                   
startupConfiguration, testSet,
+                                                                   
readTestsFromInStream, PID );
 
             if ( effectiveSystemProperties != null )
             {
@@ -806,4 +815,63 @@ public class ForkStarter
             }
         }, 0, TIMEOUT_CHECK_PERIOD_MILLIS, MILLISECONDS );
     }
+
+    static Long pid()
+    {
+        if ( JAVA_RECENT.atLeast( JAVA_9 ) )
+        {
+            Long pid = pidOnJava9();
+            if ( pid != null )
+            {
+                return pid;
+            }
+        }
+
+        if ( IS_OS_LINUX )
+        {
+            try
+            {
+                return pidOnLinux();
+            }
+            catch ( Exception e )
+            {
+                // examine PID via JMX
+            }
+        }
+
+        return pidOnJMX();
+    }
+
+    static Long pidOnJMX()
+    {
+        String processName = ManagementFactory.getRuntimeMXBean().getName();
+        if ( processName.contains( "@" ) )
+        {
+            String pid = processName.substring( 0, processName.indexOf( '@' ) 
).trim();
+            try
+            {
+                return Long.parseLong( pid );
+            }
+            catch ( NumberFormatException e )
+            {
+                return null;
+            }
+        }
+
+        return null;
+    }
+
+    static Long pidOnLinux() throws Exception
+    {
+        String pid = new File( "/proc/self" ).getCanonicalFile().getName();
+        return Long.parseLong( pid );
+    }
+
+    static Long pidOnJava9()
+    {
+        ClassLoader classLoader = currentThread().getContextClassLoader();
+        Class<?> processHandle = tryLoadClass( classLoader, 
"java.lang.ProcessHandle" );
+        String[] methodChain = { "current", "pid" };
+        return (Long) invokeMethodChain( processHandle, methodChain, null );
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporterUtils.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporterUtils.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporterUtils.java
index 36bc269..fd33d8e 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporterUtils.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporterUtils.java
@@ -19,6 +19,8 @@ package org.apache.maven.plugin.surefire.report;
  * under the License.
  */
 
+import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
+
 /**
  * Utils class for file-based reporters
  *
@@ -45,13 +47,6 @@ public final class FileReporterUtils
 
     private static String getOSSpecificIllegalChars()
     {
-        if ( System.getProperty( "os.name" ).toLowerCase().startsWith( "win" ) 
)
-        {
-            return "\\/:*?\"<>|\0";
-        }
-        else
-        {
-            return "/\0";
-        }
+        return IS_OS_WINDOWS ? "\\/:*?\"<>|\0" : "/\0";
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
index 6759367..5d970d8 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
@@ -220,8 +220,9 @@ public class BooterDeserializerProviderConfigurationTest
             test = "aTest";
         }
         final File propsTest = booterSerializer.serialize( props, 
booterConfiguration, testProviderConfiguration, test,
-                                                           
readTestsFromInStream );
+                                                           
readTestsFromInStream, 51L );
         BooterDeserializer booterDeserializer = new BooterDeserializer( new 
FileInputStream( propsTest ) );
+        assertEquals( 51L, (Object) booterDeserializer.getPluginPid() );
         return booterDeserializer.deserialize();
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
index 1ca20d2..42fb525 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -124,8 +124,9 @@ public class BooterDeserializerStartupConfigurationTest
         BooterSerializer booterSerializer = new BooterSerializer( 
forkConfiguration );
         String aTest = "aTest";
         final File propsTest =
-            booterSerializer.serialize( props, getProviderConfiguration(), 
startupConfiguration, aTest, false );
+            booterSerializer.serialize( props, getProviderConfiguration(), 
startupConfiguration, aTest, false, 51L );
         BooterDeserializer booterDeserializer = new BooterDeserializer( new 
FileInputStream( propsTest ) );
+        assertEquals( 51L, (Object) booterDeserializer.getPluginPid() );
         return booterDeserializer.getProviderConfiguration();
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
new file mode 100644
index 0000000..6cf9990
--- /dev/null
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
@@ -0,0 +1,83 @@
+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.junit.Test;
+
+import java.lang.management.ManagementFactory;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.JavaVersion.JAVA_RECENT;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Unit test for {@link ForkStarter}.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public class ForkStarterTest
+{
+    @Test
+    public void shouldBePidOnJigsaw()
+    {
+        assumeTrue( JAVA_RECENT.atLeast( JAVA_9 ) );
+
+        Long actualPid = ForkStarter.pidOnJava9();
+        String expectedPid = 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+
+        assertThat( actualPid + "" )
+                .isEqualTo( expectedPid );
+    }
+
+    @Test
+    public void shouldBePidOnLinux() throws Exception
+    {
+        assumeTrue( IS_OS_LINUX );
+
+        Long actualPid = ForkStarter.pidOnLinux();
+        String expectedPid = 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+
+        assertThat( actualPid + "" )
+                .isEqualTo( expectedPid );
+    }
+
+    @Test
+    public void shouldBePidOnJMX()
+    {
+        Long actualPid = ForkStarter.pidOnJMX();
+        String expectedPid = 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+
+        assertThat( actualPid + "" )
+                .isEqualTo( expectedPid );
+    }
+
+    @Test
+    public void shouldBePid()
+    {
+        Long actualPid = ForkStarter.pid();
+        String expectedPid = 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim();
+
+        assertThat( actualPid + "" )
+                .isEqualTo( expectedPid );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index f7cec19..a12f875 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -27,6 +27,7 @@ import 
org.apache.maven.plugin.surefire.SurefirePropertiesTest;
 import 
org.apache.maven.plugin.surefire.booterclient.BooterDeserializerProviderConfigurationTest;
 import 
org.apache.maven.plugin.surefire.booterclient.BooterDeserializerStartupConfigurationTest;
 import org.apache.maven.plugin.surefire.booterclient.ForkConfigurationTest;
+import org.apache.maven.plugin.surefire.booterclient.ForkStarterTest;
 import org.apache.maven.plugin.surefire.booterclient.ForkingRunListenerTest;
 import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
 import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
@@ -72,7 +73,8 @@ import org.junit.runners.Suite;
     TestLessInputStreamBuilderTest.class,
     SPITest.class,
     SurefireReflectorTest.class,
-    SurefireHelperTest.class
+    SurefireHelperTest.class,
+    ForkStarterTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/pom.xml b/maven-surefire-plugin/pom.xml
index 62ec4a7..2a186e3 100644
--- a/maven-surefire-plugin/pom.xml
+++ b/maven-surefire-plugin/pom.xml
@@ -45,26 +45,9 @@
 
   <dependencies>
     <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven.surefire</groupId>
       <artifactId>maven-surefire-common</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.apache.maven.surefire</groupId>
-      <artifactId>surefire-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-toolchain</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.plugin-tools</groupId>
-      <artifactId>maven-plugin-annotations</artifactId>
-      <scope>compile</scope>
-    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-plugin/src/site/apt/examples/shutdown.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/shutdown.apt.vm 
b/maven-surefire-plugin/src/site/apt/examples/shutdown.apt.vm
index a546853..7126247 100644
--- a/maven-surefire-plugin/src/site/apt/examples/shutdown.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/shutdown.apt.vm
@@ -39,8 +39,32 @@ Shutdown of Forked JVM
 
 * Pinging forked JVM
 
+  << Since ${thisPlugin} Plugin 2.20.1 ping is platform dependent and 
fallbacks to old mechanism if PID of Maven
+  process or platform is not recognized, native commands fail in Java. >>
+
+  Simply the mechanism checks the <<< Maven PID >>> is still alive and it is 
not reused by OS in another application.
+  If Maven process has died, the forked JVM is killed.
+
+  << Implementation: >> The <<< Maven PID >>> is determined by:
+
+   * resolving the link <<< /proc/self >>> on Linux, or
+
+   * the JMX call <<< ManagementFactory.getRuntimeMXBean().getName() >>>, or
+
+   * Java 9 call <<< ProcessHandle.current().pid() >>>.
+
+   []
+
+   On Unix like systems the process' uptime is determined by native command 
<<< (/usr)/bin/ps -o etime= -p [PID] >>>.
+
+   On Windows the start time is determined using <<< wmic process where 
(ProcessId=[PID]) get CreationDate >>>
+   in the forked JVM.
+
+
+  << Since ${thisPlugin} Plugin 2.19 the old mechanism is significantly 
slower: >>
+
   The master process sends NOOP command to a forked JVM every 10 seconds.
-  Forked JVM is waiting for the command every 20 seconds.
+  Forked JVM is waiting for the command every 30 seconds.
   If the master process is killed (received SIGKILL signal) or shutdown 
   (pressed CTRL+C, received SIGTERM signal), forked JVM is killed after
   timing out waiting period.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/maven-surefire-report-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-report-plugin/pom.xml 
b/maven-surefire-report-plugin/pom.xml
index a4fe7e2..93a2e80 100644
--- a/maven-surefire-report-plugin/pom.xml
+++ b/maven-surefire-report-plugin/pom.xml
@@ -48,10 +48,6 @@
 
   <dependencies>
     <dependency>
-      <groupId>org.apache.maven.surefire</groupId>
-      <artifactId>surefire-logger-api</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-project</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 962a5bf..397d5d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,9 @@
     <mavenVersion>2.2.1</mavenVersion>
     <!-- <shadedVersion>2.12.4</shadedVersion> commented out due to 
https://issues.apache.org/jira/browse/MRELEASE-799 -->
     <mavenPluginPluginVersion>3.3</mavenPluginPluginVersion>
+    <commonsLang3Version>3.5</commonsLang3Version>
+    <commonsIoVersion>2.5</commonsIoVersion>
+    <mavenSharedUtilsVersion>0.9</mavenSharedUtilsVersion>
     
<maven.surefire.scm.devConnection>scm:git:https://git-wip-us.apache.org/repos/asf/maven-surefire.git</maven.surefire.scm.devConnection>
     <maven.site.path>surefire-archives/surefire-LATEST</maven.site.path>
   </properties>
@@ -105,12 +108,12 @@
       <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
-        <version>3.1</version>
+        <version>${commonsLang3Version}</version>
       </dependency>
       <dependency>
         <groupId>commons-io</groupId>
         <artifactId>commons-io</artifactId>
-        <version>2.2</version>
+        <version>${commonsIoVersion}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.maven.surefire</groupId>
@@ -215,7 +218,13 @@
       <dependency>
         <groupId>org.apache.maven.shared</groupId>
         <artifactId>maven-shared-utils</artifactId>
-        <version>0.9</version>
+        <version>${mavenSharedUtilsVersion}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+          </exclusion>
+        </exclusions>
       </dependency>
       <dependency>
         <groupId>org.apache.maven.shared</groupId>
@@ -377,7 +386,7 @@
         </plugin>
         <plugin>
           <artifactId>maven-shade-plugin</artifactId>
-          <version>1.5</version>
+          <version>3.0.0</version>
         </plugin>
         <plugin>
           <artifactId>maven-plugin-plugin</artifactId>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-api/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index 7e407d2..96c5be3 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -40,6 +40,11 @@
       <groupId>org.apache.maven.shared</groupId>
       <artifactId>maven-shared-utils</artifactId>
     </dependency>
+    <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -74,7 +79,6 @@
               <artifactSet>
                 <includes>
                   <include>org.apache.maven.shared:maven-shared-utils</include>
-                  <include>commons-lang:commons-lang</include>
                 </includes>
               </artifactSet>
               <relocations>
@@ -82,10 +86,6 @@
                   <pattern>org.apache.maven.shared</pattern>
                   
<shadedPattern>org.apache.maven.surefire.shade.org.apache.maven.shared</shadedPattern>
                 </relocation>
-                <relocation>
-                  <pattern>org.apache.commons.lang</pattern>
-                  
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.lang</shadedPattern>
-                </relocation>
               </relocations>
             </configuration>
           </execution>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
----------------------------------------------------------------------
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 ed7d4fa..c3d80ea 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
@@ -438,7 +438,7 @@ public final class CommandReader
                     DumpErrorSingleton.getSingleton().dumpStreamException( e, 
msg );
 
                     exitByConfiguration();
-                    // does not go to finally
+                    // does not go to finally for non-default config: 
Shutdown.EXIT or Shutdown.KILL
                 }
             }
             catch ( IOException e )
@@ -493,7 +493,7 @@ public final class CommandReader
                 {
                     Runtime.getRuntime().halt( 1 );
                 }
-                // else is default: should not happen; otherwise you missed 
enum case
+                // else is default: other than Shutdown.DEFAULT should not 
happen; otherwise you missed enum case
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
 
b/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
index 6844dda..a0dcd66 100644
--- 
a/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
+++ 
b/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
@@ -28,10 +28,6 @@ import java.lang.reflect.Method;
  */
 public final class ReflectionUtils
 {
-    private static final Class[] NO_ARGS = new Class[0];
-
-    private static final Object[] NO_ARGS_VALUES = new Object[0];
-
     private ReflectionUtils()
     {
         throw new IllegalStateException( "no instantiable constructor" );
@@ -68,8 +64,8 @@ public final class ReflectionUtils
 
     public static Object invokeGetter( Object instance, String methodName )
     {
-        final Method method = getMethod( instance, methodName, NO_ARGS );
-        return invokeMethodWithArray( instance, method, NO_ARGS_VALUES );
+        final Method method = getMethod( instance, methodName );
+        return invokeMethodWithArray( instance, method );
     }
 
     public static Constructor getConstructor( Class<?> clazz, Class<?>... 
arguments )
@@ -245,4 +241,45 @@ public final class ReflectionUtils
             throw new SurefireReflectionException( e );
         }
     }
+
+    /**
+     * Invoker of public static no-argument method.
+     *
+     * @param clazz         class on which public static no-argument {@code 
methodName} is invoked
+     * @param methodName    public static no-argument method to be called
+     * @return value returned by {@code methodName}
+     * @throws RuntimeException if no such method found
+     * @throws SurefireReflectionException if the method could not be called 
or threw an exception
+     */
+    public static Object invokeStaticMethod( Class<?> clazz, String methodName 
)
+    {
+        Method method = getMethod( clazz, methodName );
+        return invokeMethodWithArray( null, method );
+    }
+
+    /**
+     * Method chain invoker.
+     *
+     * @param firstStaticClass    class to start method chain
+     * @param noArgMethodNames    chain of public methods to call
+     * @param fallback            returned value if a chain could not be 
invoked due to an error
+     * @return successfully returned value from the last method call; {@code 
fallback} otherwise
+     */
+    public static Object invokeMethodChain( Class<?> firstStaticClass, 
String[] noArgMethodNames, Object fallback )
+    {
+        Object obj = null;
+        try
+        {
+            for ( int i = 0, len = noArgMethodNames.length; i < len; i++ )
+            {
+                String methodName = noArgMethodNames[i];
+                obj = i == 0 ? invokeStaticMethod( firstStaticClass, 
methodName ) : invokeGetter( obj, methodName );
+            }
+            return obj;
+        }
+        catch ( RuntimeException e )
+        {
+            return fallback;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java 
b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index dbf46ea..9558bf8 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -32,6 +32,7 @@ import 
org.apache.maven.surefire.testset.FundamentalFilterTest;
 import org.apache.maven.surefire.testset.ResolvedTestTest;
 import org.apache.maven.surefire.testset.TestListResolverTest;
 import org.apache.maven.surefire.util.DefaultDirectoryScannerTest;
+import org.apache.maven.surefire.util.ReflectionUtilsTest;
 import org.apache.maven.surefire.util.RunOrderCalculatorTest;
 import org.apache.maven.surefire.util.RunOrderTest;
 import org.apache.maven.surefire.util.ScanResultTest;
@@ -70,7 +71,8 @@ import org.junit.runners.Suite;
     SpecificTestClassFilterTest.class,
     FundamentalFilterTest.class,
     SystemUtilsTest.class,
-    ImmutableMapTest.class
+    ImmutableMapTest.class,
+    ReflectionUtilsTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-api/src/test/java/org/apache/maven/surefire/util/ReflectionUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/test/java/org/apache/maven/surefire/util/ReflectionUtilsTest.java
 
b/surefire-api/src/test/java/org/apache/maven/surefire/util/ReflectionUtilsTest.java
new file mode 100644
index 0000000..89bc205
--- /dev/null
+++ 
b/surefire-api/src/test/java/org/apache/maven/surefire/util/ReflectionUtilsTest.java
@@ -0,0 +1,110 @@
+package org.apache.maven.surefire.util;
+
+/*
+ * 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 static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Unit test for {@link ReflectionUtils}.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public class ReflectionUtilsTest
+{
+    @Test(expected = RuntimeException.class)
+    public void shouldNotInvokeStaticMethod()
+    {
+        ReflectionUtils.invokeStaticMethod( ReflectionUtilsTest.class, 
"notCallable" );
+    }
+
+    @Test
+    public void shouldInvokeStaticMethod()
+    {
+        Object o = ReflectionUtils.invokeStaticMethod( 
ReflectionUtilsTest.class, "callable" );
+        assertThat( o )
+                .isEqualTo( 3L );
+    }
+
+    @Test
+    public void shouldInvokeMethodChain()
+    {
+        String[] chain = { "current", "pid" };
+        Object o = ReflectionUtils.invokeMethodChain( A.class, chain, null );
+        assertThat( o )
+                .isEqualTo( 3L );
+
+        String[] longChain = { "current", "createB", "pid" };
+        o = ReflectionUtils.invokeMethodChain( A.class, longChain, null );
+        assertThat( o )
+                .isEqualTo( 1L );
+    }
+
+    @Test
+    public void shouldInvokeFallbackOnMethodChain()
+    {
+        String[] chain = { "current", "abc" };
+        Object o = ReflectionUtils.invokeMethodChain( A.class, chain, 5L );
+        assertThat( o )
+                .isEqualTo( 5L );
+
+        String[] longChain = { "current", "createB", "abc" };
+        o = ReflectionUtils.invokeMethodChain( A.class, longChain, 6L );
+        assertThat( o )
+                .isEqualTo( 6L );
+    }
+
+    private static void notCallable()
+    {
+    }
+
+    public static long callable()
+    {
+        return 3L;
+    }
+
+    public static class A
+    {
+        public static A current()
+        {
+            return new A();
+        }
+
+        public long pid()
+        {
+            return 3L;
+        }
+
+        public B createB()
+        {
+            return new B();
+        }
+    }
+
+    public static class B
+    {
+        public long pid()
+        {
+            return 1L;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-booter/pom.xml b/surefire-booter/pom.xml
index b79cceb..1dc7591 100644
--- a/surefire-booter/pom.xml
+++ b/surefire-booter/pom.xml
@@ -35,6 +35,20 @@
     <dependency>
       <groupId>org.apache.maven.surefire</groupId>
       <artifactId>surefire-api</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.maven.shared</groupId>
+          <artifactId>maven-shared-utils</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
     </dependency>
   </dependencies>
 
@@ -69,13 +83,18 @@
               <minimizeJar>true</minimizeJar>
               <artifactSet>
                 <includes>
-                  <include>commons-lang:commons-lang</include>
+                  <include>org.apache.commons:commons-lang3</include>
+                  <include>commons-io:commons-io</include>
                 </includes>
               </artifactSet>
               <relocations>
                 <relocation>
-                  <pattern>org.apache.commons.lang</pattern>
-                  
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.lang</shadedPattern>
+                  <pattern>org.apache.commons.lang3</pattern>
+                  
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.lang3</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.io</pattern>
+                  
<shadedPattern>org.apache.maven.surefire.shade.org.apache.commons.io</shadedPattern>
                 </relocation>
               </relocations>
             </configuration>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
index c21edf8..3551910 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
@@ -56,4 +56,5 @@ public final class BooterConstants
     public static final String FAIL_FAST_COUNT = "failFastCount";
     public static final String SHUTDOWN = "shutdown";
     public static final String SYSTEM_EXIT_TIMEOUT = "systemExitTimeout";
+    public static final String PLUGIN_PID = "pluginPid";
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
index 8fa760b..75aad1f 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -58,6 +58,14 @@ public class BooterDeserializer
         properties = SystemPropertyManager.loadProperties( inputStream );
     }
 
+    /**
+     * @return PID of Maven process where plugin is executed; or null if PID 
could not be determined.
+     */
+    public Long getPluginPid()
+    {
+        return properties.getLongProperty( PLUGIN_PID );
+    }
+
     public ProviderConfiguration deserialize()
     {
         final File reportsDirectory = new File( properties.getProperty( 
REPORTSDIRECTORY ) );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/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 1e3863e..c19a698 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,9 +73,9 @@ import static 
org.apache.maven.surefire.util.internal.StringUtils.encodeStringFo
  */
 public final class ForkedBooter
 {
-    private static final long DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS = 30;
-    private static final long PING_TIMEOUT_IN_SECONDS = 20;
-    private static final long ONE_SECOND_IN_MILLIS = 1000;
+    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 CommandReader COMMAND_READER = 
startupMasterProcessReader();
 
     private static volatile ScheduledThreadPoolExecutor jvmTerminator;
@@ -89,8 +89,8 @@ public final class ForkedBooter
      */
     public static void main( String... args )
     {
-        final ExecutorService pingScheduler = isDebugging() ? null : 
listenToShutdownCommands();
         final PrintStream originalOut = out;
+        ExecutorService pingScheduler = null;
         try
         {
             final String tmpDir = args[0];
@@ -99,6 +99,9 @@ public final class ForkedBooter
 
             BooterDeserializer booterDeserializer =
                     new BooterDeserializer( 
createSurefirePropertiesIfFileExists( tmpDir, surefirePropsFileName ) );
+
+            pingScheduler = isDebugging() ? null : listenToShutdownCommands( 
booterDeserializer.getPluginPid() );
+
             if ( args.length > 3 )
             {
                 final String effectiveSystemPropertiesFileName = args[3];
@@ -202,17 +205,43 @@ public final class ForkedBooter
         return getReader();
     }
 
-    private static ExecutorService listenToShutdownCommands()
+    private static ExecutorService listenToShutdownCommands( Long pluginPid )
     {
         COMMAND_READER.addShutdownListener( createExitHandler() );
         AtomicBoolean pingDone = new AtomicBoolean( true );
         COMMAND_READER.addNoopListener( createPingHandler( pingDone ) );
-        Runnable pingJob = createPingJob( pingDone );
         ScheduledExecutorService pingScheduler = createPingScheduler();
-        pingScheduler.scheduleAtFixedRate( pingJob, 0, 
PING_TIMEOUT_IN_SECONDS, SECONDS );
+        PpidChecker checker = new PpidChecker( pluginPid );
+        pingScheduler.scheduleWithFixedDelay( processCheckerJob( checker ), 
0L, 1L, SECONDS );
+        pingScheduler.scheduleAtFixedRate( createPingJob( pingDone, checker ), 
0L, PING_TIMEOUT_IN_SECONDS, SECONDS );
         return pingScheduler;
     }
 
+    private static Runnable processCheckerJob( final PpidChecker 
processChecker )
+    {
+        return new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                if ( processChecker != null )
+                {
+                    try
+                    {
+                        if ( processChecker.canUse() && 
!processChecker.isProcessAlive() )
+                        {
+                            kill();
+                        }
+                    }
+                    catch ( Exception e )
+                    {
+                        // nothing to do
+                    }
+                }
+            }
+        };
+    }
+
     private static CommandListener createPingHandler( final AtomicBoolean 
pingDone )
     {
         return new CommandListener()
@@ -246,22 +275,30 @@ public final class ForkedBooter
         };
     }
 
-    private static Runnable createPingJob( final AtomicBoolean pingDone  )
+    private static Runnable createPingJob( final AtomicBoolean pingDone, final 
PpidChecker processChecker  )
     {
         return new Runnable()
         {
             @Override
             public void run()
             {
-                boolean hasPing = pingDone.getAndSet( false );
-                if ( !hasPing )
+                if ( !canUseNewPingMechanism( processChecker ) )
                 {
-                    kill();
+                    boolean hasPing = pingDone.getAndSet( false );
+                    if ( !hasPing )
+                    {
+                        kill();
+                    }
                 }
             }
         };
     }
 
+    private static boolean canUseNewPingMechanism( PpidChecker processChecker )
+    {
+        return processChecker != null && processChecker.canUse();
+    }
+
     private static void encodeAndWriteToOutput( String string, PrintStream out 
)
     {
         byte[] encodeBytes = encodeStringForForkCommunication( string );
@@ -275,14 +312,18 @@ public final class ForkedBooter
 
     private static void kill()
     {
+        kill( 1 );
+    }
+
+    private static void kill( int returnCode )
+    {
         COMMAND_READER.stop();
-        Runtime.getRuntime().halt( 1 );
+        Runtime.getRuntime().halt( returnCode );
     }
 
     private static void exit( int returnCode )
     {
         launchLastDitchDaemonShutdownThread( returnCode );
-        COMMAND_READER.stop();
         System.exit( returnCode );
     }
 
@@ -357,8 +398,8 @@ public final class ForkedBooter
     {
         ThreadFactory threadFactory = newDaemonThreadFactory( "ping-" + 
PING_TIMEOUT_IN_SECONDS + "s" );
         ScheduledThreadPoolExecutor executor = new 
ScheduledThreadPoolExecutor( 1, threadFactory );
-        executor.setMaximumPoolSize( 1 );
-        executor.prestartCoreThread();
+        executor.setKeepAliveTime( 3L, SECONDS );
+        executor.setMaximumPoolSize( 2 );
         return executor;
     }
 
@@ -370,8 +411,7 @@ public final class ForkedBooter
                                             @Override
                                             public void run()
                                             {
-                                                COMMAND_READER.stop();
-                                                Runtime.getRuntime().halt( 
returnCode );
+                                                kill( returnCode );
                                             }
                                         }, systemExitTimeoutInSeconds, SECONDS
         );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
new file mode 100644
index 0000000..e1465db
--- /dev/null
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
@@ -0,0 +1,321 @@
+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 java.io.File;
+import java.io.IOException;
+import java.util.Queue;
+import java.util.Scanner;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.lang.Character.isDigit;
+import static java.lang.Long.parseLong;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.regex.Pattern.compile;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
+import static org.apache.maven.surefire.booter.ProcessInfo.ERR_PROCESS_INFO;
+import static 
org.apache.maven.surefire.booter.ProcessInfo.INVALID_PROCESS_INFO;
+
+/**
+ * Recognizes PID of Plugin process and determines lifetime.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+final class PpidChecker
+{
+    private static final String WMIC_CREATION_DATE = "CreationDate";
+
+    private final Queue<Process> destroyableCommands = new 
ConcurrentLinkedQueue<Process>();
+
+    /**
+     * The etime is in the form of [[dd-]hh:]mm:ss on Unix like systems.
+     */
+    static final Pattern UNIX_CMD_OUT_PATTERN = compile( 
"^(((\\d+)-)?(\\d{2}):)?(\\d{2}):(\\d{2})$" );
+
+    private final long pluginPid;
+
+    private volatile ProcessInfo pluginProcessInfo;
+
+    PpidChecker( long pluginPid )
+    {
+        this.pluginPid = pluginPid;
+    }
+
+    boolean canUse()
+    {
+        return pluginProcessInfo == null ? IS_OS_WINDOWS || IS_OS_UNIX : 
pluginProcessInfo.isValid();
+    }
+
+    /**
+     * This method can be called only after {@link #canUse()} has returned 
{@code true}.
+     *
+     * @return {@code true} if parent process is alive; {@code false} otherwise
+     * @throws IllegalStateException if {@link #canUse()} returns {@code 
false} or {@link ProcessInfo} is erroneous
+     */
+    @SuppressWarnings( "unchecked" )
+    boolean isProcessAlive()
+    {
+        if ( !canUse() )
+        {
+            throw new IllegalStateException( "irrelevant to call 
isProcessAlive()" );
+        }
+
+        if ( IS_OS_WINDOWS )
+        {
+            ProcessInfo previousPluginProcessInfo = pluginProcessInfo;
+            pluginProcessInfo = windows();
+            if ( pluginProcessInfo.hasError() )
+            {
+                throw new IllegalStateException( "error to read process" );
+            }
+            // let's compare creation time, should be same unless killed or 
PID is reused by OS into another process
+            return pluginProcessInfo.isValid()
+                           && ( previousPluginProcessInfo == null
+                                        || pluginProcessInfo.isTimeEqualTo( 
previousPluginProcessInfo ) );
+        }
+        else if ( IS_OS_UNIX )
+        {
+            ProcessInfo previousPluginProcessInfo = pluginProcessInfo;
+            pluginProcessInfo = unix();
+            if ( pluginProcessInfo.hasError() )
+            {
+                throw new IllegalStateException();
+            }
+            // let's compare elapsed time, should be greater or equal if 
parent process is the same and still alive
+            return pluginProcessInfo.isValid()
+                           && ( previousPluginProcessInfo == null
+                                        || pluginProcessInfo.isTimeEqualTo( 
previousPluginProcessInfo )
+                                        || pluginProcessInfo.isTimeAfter( 
previousPluginProcessInfo ) );
+        }
+
+        throw new IllegalStateException();
+    }
+
+    // https://www.freebsd.org/cgi/man.cgi?ps(1)
+    // etimes elapsed running time, in decimal integer seconds
+
+    // http://manpages.ubuntu.com/manpages/xenial/man1/ps.1.html
+    // etimes elapsed time since the process was started, in seconds.
+
+    // 
http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/test/java/lang/ProcessBuilder/Basic.java#L167
+    ProcessInfo unix()
+    {
+        ProcessInfoConsumer reader = new ProcessInfoConsumer()
+        {
+            @Override
+            ProcessInfo consumeLine( String line, ProcessInfo 
previousProcessInfo )
+            {
+                if ( !previousProcessInfo.isValid() )
+                {
+                    Matcher matcher = UNIX_CMD_OUT_PATTERN.matcher( line );
+                    if ( matcher.matches() )
+                    {
+                        long pidUptime = fromDays( matcher )
+                                                 + fromHours( matcher )
+                                                 + fromMinutes( matcher )
+                                                 + fromSeconds( matcher );
+                        return ProcessInfo.unixProcessInfo( pluginPid, 
pidUptime );
+                    }
+                }
+                return previousProcessInfo;
+            }
+        };
+
+        return reader.execute( "/bin/sh", "-c", unixPathToPS() + " -o etime= 
-p " + pluginPid );
+    }
+
+    ProcessInfo windows()
+    {
+        ProcessInfoConsumer reader = new ProcessInfoConsumer()
+        {
+            private boolean hasHeader;
+
+            @Override
+            ProcessInfo consumeLine( String line, ProcessInfo 
previousProcessInfo )
+            {
+                if ( !previousProcessInfo.isValid() )
+                {
+                    StringTokenizer args = new StringTokenizer( line );
+                    if ( args.countTokens() == 1 )
+                    {
+                        if ( hasHeader )
+                        {
+                            String startTimestamp = args.nextToken();
+                            return ProcessInfo.windowsProcessInfo( pluginPid, 
startTimestamp );
+                        }
+                        else
+                        {
+                            hasHeader = WMIC_CREATION_DATE.equals( 
args.nextToken() );
+                        }
+                    }
+                }
+                return previousProcessInfo;
+            }
+        };
+        String pid = String.valueOf( pluginPid );
+        return reader.execute( "CMD", "/A", "/X", "/C",
+                                     "wmic process where (ProcessId=" + pid + 
") get " + WMIC_CREATION_DATE );
+    }
+
+    void destroyActiveCommands()
+    {
+        for ( Process p = destroyableCommands.poll(); p != null; p = 
destroyableCommands.poll() )
+        {
+            p.destroy();
+        }
+    }
+
+    static String unixPathToPS()
+    {
+        return new File( "/usr/bin/ps" ).canExecute() ? "/usr/bin/ps" : 
"/bin/ps";
+    }
+
+    static long fromDays( Matcher matcher )
+    {
+        String s = matcher.group( 3 );
+        return s == null ? 0L : DAYS.toSeconds( parseLong( s ) );
+    }
+
+    static long fromHours( Matcher matcher )
+    {
+        String s = matcher.group( 4 );
+        return s == null ? 0L : HOURS.toSeconds( parseLong( s ) );
+    }
+
+    static long fromMinutes( Matcher matcher )
+    {
+        String s = matcher.group( 5 );
+        return s == null ? 0L : MINUTES.toSeconds( parseLong( s ) );
+    }
+
+    static long fromSeconds( Matcher matcher )
+    {
+        String s = matcher.group( 6 );
+        return s == null ? 0L : parseLong( s );
+    }
+
+    static String extractNumberFromBegin( String line )
+    {
+        StringBuilder number = new StringBuilder();
+        for ( int i = 0, len = line.length(); i < len; i++ )
+        {
+            char c = line.charAt( i );
+            if ( isDigit( c ) )
+            {
+                number.append( c );
+            }
+            else
+            {
+                break;
+            }
+        }
+        return number.toString();
+    }
+
+    static String extractNumberFromEnd( String line )
+    {
+        StringBuilder number = new StringBuilder();
+        for ( int i = line.length() - 1; i >= 0; i-- )
+        {
+            char c = line.charAt( i );
+            if ( isDigit( c ) )
+            {
+                number.insert( 0, c );
+            }
+            else
+            {
+                break;
+            }
+        }
+        return number.toString();
+    }
+
+    private static void checkValid( Scanner scanner )
+            throws IOException
+    {
+        IOException exception = scanner.ioException();
+        if ( exception != null )
+        {
+            throw exception;
+        }
+    }
+
+    /**
+     * Reads standard output from {@link Process}.
+     * <br>
+     * The artifact maven-shared-utils has non-daemon Threads which is an 
issue in Surefire to satisfy System.exit.
+     * This implementation is taylor made without using any Thread.
+     * It's easy to destroy Process from other Thread.
+     */
+    private abstract class ProcessInfoConsumer
+    {
+        abstract ProcessInfo consumeLine( String line, ProcessInfo 
previousProcessInfo );
+
+        ProcessInfo execute( String... command )
+        {
+            ProcessBuilder processBuilder = new ProcessBuilder( command );
+            processBuilder.redirectErrorStream( true );
+            Process process = null;
+            ProcessInfo processInfo = INVALID_PROCESS_INFO;
+            try
+            {
+                process = processBuilder.start();
+                destroyableCommands.add( process );
+                Scanner scanner = new Scanner( process.getInputStream() );
+                while ( scanner.hasNextLine() )
+                {
+                    String line = scanner.nextLine().trim();
+                    processInfo = consumeLine( line, processInfo );
+                }
+                checkValid( scanner );
+                int exitCode = process.waitFor();
+                return exitCode == 0 ? processInfo : ERR_PROCESS_INFO;
+            }
+            catch ( IOException e )
+            {
+                return ERR_PROCESS_INFO;
+            }
+            catch ( InterruptedException e )
+            {
+                return ERR_PROCESS_INFO;
+            }
+            finally
+            {
+                if ( process != null )
+                {
+                    destroyableCommands.remove( process );
+                    process.destroy();
+                    closeQuietly( process.getInputStream() );
+                    closeQuietly( process.getErrorStream() );
+                    closeQuietly( process.getOutputStream() );
+                }
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
new file mode 100644
index 0000000..4066e84
--- /dev/null
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
@@ -0,0 +1,110 @@
+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 static 
org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
+
+/**
+ * Immutable object which encapsulates PID and elapsed time (Unix) or start 
time (Windows).
+ * <br>
+ * Methods
+ * ({@link #getPID()}, {@link #getTime()}, {@link #isTimeAfter(ProcessInfo)}, 
{@link #isTimeEqualTo(ProcessInfo)})
+ * throw {@link IllegalStateException} if {@link #isValid()} returns {@code 
false}.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+final class ProcessInfo
+{
+    static final ProcessInfo INVALID_PROCESS_INFO = new ProcessInfo( null, 
null, false );
+    static final ProcessInfo ERR_PROCESS_INFO = new ProcessInfo( null, null, 
true );
+
+    /**
+     * On Unix we do not get PID due to the command is interested only to 
etime of PPID:
+     * <br>
+     * <pre>/bin/ps -o etime= -p 123</pre>
+     */
+    static ProcessInfo unixProcessInfo( long pid, long etime )
+    {
+        return new ProcessInfo( pid, etime, false );
+    }
+
+    static ProcessInfo windowsProcessInfo( long pid, String startTimestamp )
+    {
+        return new ProcessInfo( pid, requireNonNull( startTimestamp, 
"startTimestamp is NULL" ), false );
+    }
+
+    private final Long pid;
+    private final Comparable time;
+    private final boolean error;
+
+    private ProcessInfo( Long pid, Comparable time, boolean error )
+    {
+        this.pid = pid;
+        this.time = time;
+        this.error = error;
+    }
+
+    boolean hasError()
+    {
+        return error;
+    }
+
+    boolean isValid()
+    {
+        return !error && pid != null && time != null;
+    }
+
+    long getPID()
+    {
+        checkValid();
+        return pid;
+    }
+
+    Comparable getTime()
+    {
+        checkValid();
+        return time;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    boolean isTimeEqualTo( ProcessInfo that )
+    {
+        checkValid();
+        that.checkValid();
+        return this.time.compareTo( that.time ) == 0;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    boolean isTimeAfter( ProcessInfo that )
+    {
+        checkValid();
+        that.checkValid();
+        return this.time.compareTo( that.time ) > 0;
+    }
+
+    private void checkValid()
+    {
+        if ( !isValid() )
+        {
+            throw new IllegalStateException( "invalid process info" );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java
index 41b4850..7cf04bc 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PropertiesWrapper.java
@@ -70,6 +70,12 @@ public class PropertiesWrapper
         return Integer.parseInt( properties.get( propertyName ) );
     }
 
+    public Long getLongProperty( String propertyName )
+    {
+        String number = properties.get( propertyName );
+        return number == null ? null : Long.parseLong( number );
+    }
+
     public File getFileProperty( String key )
     {
         final String property = getProperty( key );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
----------------------------------------------------------------------
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 2bdcf21..b08423f 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
@@ -34,7 +34,8 @@ import org.junit.runners.Suite;
     ClasspathTest.class,
     CommandReaderTest.class,
     PropertiesWrapperTest.class,
-    SurefireReflectorTest.class
+    SurefireReflectorTest.class,
+    PpidCheckerTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
new file mode 100644
index 0000000..bc8b501
--- /dev/null
+++ 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
@@ -0,0 +1,163 @@
+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 java.lang.management.ManagementFactory;
+import java.util.regex.Matcher;
+
+import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX;
+import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Testing {@link PpidChecker} on a platform.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public class PpidCheckerTest
+{
+    @Test
+    public void shouldHavePpidAsWindows()
+    {
+        assumeTrue( IS_OS_WINDOWS );
+
+        long expectedPid = Long.parseLong( 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim() );
+
+        PpidChecker checker = new PpidChecker( expectedPid );
+        ProcessInfo processInfo = checker.windows();
+
+        assertThat( processInfo )
+                .isNotNull();
+
+        assertThat( checker.canUse() )
+                .isTrue();
+
+        assertThat( checker.isProcessAlive() )
+                .isTrue();
+
+        assertThat( processInfo.getPID() )
+                .isEqualTo( expectedPid );
+
+        assertThat( processInfo.getTime() )
+                .isNotNull();
+    }
+
+    @Test
+    public void shouldHavePpidAsUnix()
+    {
+        assumeTrue( IS_OS_UNIX );
+
+        long expectedPid = Long.parseLong( 
ManagementFactory.getRuntimeMXBean().getName().split( "@" )[0].trim() );
+
+        PpidChecker checker = new PpidChecker( expectedPid );
+        ProcessInfo processInfo = checker.unix();
+
+        assertThat( processInfo )
+                .isNotNull();
+
+        assertThat( checker.canUse() )
+                .isTrue();
+
+        assertThat( checker.isProcessAlive() )
+                .isTrue();
+
+        assertThat( processInfo.getPID() )
+                .isEqualTo( expectedPid );
+
+        assertThat( processInfo.getTime() )
+                .isNotNull();
+    }
+
+    @Test
+    public void shouldParseEtime()
+    {
+        Matcher m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "38" );
+        assertThat( m.matches() )
+                .isFalse();
+
+        m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "05:38" );
+        assertThat( m.matches() )
+                .isTrue();
+        assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L );
+        assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 0L );
+        assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L );
+        assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L );
+
+        m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "00:05:38" );
+        assertThat( m.matches() )
+                .isTrue();
+        assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L );
+        assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 0L );
+        assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L );
+        assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L );
+
+        m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "01:05:38" );
+        assertThat( m.matches() )
+                .isTrue();
+        assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 0L );
+        assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 3600L );
+        assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L );
+        assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L );
+
+        m = PpidChecker.UNIX_CMD_OUT_PATTERN.matcher( "02-01:05:38" );
+        assertThat( m.matches() )
+                .isTrue();
+        assertThat( PpidChecker.fromDays( m ) ).isEqualTo( 2 * 24 * 3600L );
+        assertThat( PpidChecker.fromHours( m ) ).isEqualTo( 3600L );
+        assertThat( PpidChecker.fromMinutes( m ) ).isEqualTo( 300L );
+        assertThat( PpidChecker.fromSeconds( m ) ).isEqualTo( 38L );
+    }
+
+    @Test
+    public void shouldExtractNumberFromBegin()
+    {
+        String num = PpidChecker.extractNumberFromBegin( "123 abc" );
+        assertThat( num )
+                .isEqualTo( "123" );
+    }
+
+    @Test
+    public void shouldNotExtractNumberFromBegin()
+    {
+        String num = PpidChecker.extractNumberFromBegin( " 123 abc" );
+        assertThat( num )
+                .isEmpty();
+    }
+
+    @Test
+    public void shouldExtractNumberFromEnd()
+    {
+        String num = PpidChecker.extractNumberFromEnd( "abc 123" );
+        assertThat( num )
+                .isEqualTo( "123" );
+    }
+
+    @Test
+    public void shouldNotExtractNumberFromEnd()
+    {
+        String num = PpidChecker.extractNumberFromEnd( "abs 123 " );
+        assertThat( num )
+                .isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/cb5abc50/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
----------------------------------------------------------------------
diff --git 
a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
 
b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
index 1fa88f6..f051c1c 100644
--- 
a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
+++ 
b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1295AttributeJvmCrashesToTestsIT.java
@@ -27,8 +27,9 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.util.Iterator;
-import java.util.Locale;
 
+import static org.apache.commons.lang.SystemUtils.IS_OS_LINUX;
+import static org.apache.commons.lang.SystemUtils.IS_OS_MAC_OSX;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
@@ -46,8 +47,7 @@ public class Surefire1295AttributeJvmCrashesToTestsIT
     @Before
     public void skipWindows()
     {
-        String os = System.getProperty( "os.name" ).toLowerCase( Locale.ROOT );
-        assumeTrue( os.equals( "mac os x" ) || os.equals( "linux" ) /*||  
os.contains( "windows" )*/ );
+        assumeTrue( IS_OS_LINUX || IS_OS_MAC_OSX );
     }
 
     @Test

Reply via email to