You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kr...@apache.org on 2013/01/21 20:08:11 UTC
[1/2] git commit: [SUREFIRE-946] prevent hanging main process if
forked process was killed (softly)
[SUREFIRE-946] prevent hanging main process if forked process was killed (softly)
Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/463f37b3
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/463f37b3
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/463f37b3
Branch: refs/heads/master
Commit: 463f37b30dcc59de7c8550774c4dff19c96112fa
Parents: 9cd2acb
Author: agudian <an...@gmail.com>
Authored: Sat Jan 5 21:13:12 2013 +0100
Committer: Kristian Rosenvold <kr...@apache.org>
Committed: Mon Jan 21 18:10:36 2013 +0100
----------------------------------------------------------------------
.../plugin/surefire/booterclient/ForkStarter.java | 20 +-
.../lazytestprovider/TestProvidingInputStream.java | 248 +++++++-------
.../surefire/booterclient/output/ForkClient.java | 12 -
pom.xml | 2 +-
.../maven/surefire/booter/ForkingRunListener.java | 2 -
.../apache/maven/surefire/booter/ForkedBooter.java | 74 +----
.../maven/surefire/its/CrashDetectionIT.java | 5 +
.../maven/surefire/its/fixture/MavenLauncher.java | 6 +-
.../surefire/its/fixture/SurefireLauncher.java | 7 +-
...Surefire946KillMainProcessInReusableForkIT.java | 71 ++++
.../test/java/junit44/environment/BasicTest.java | 8 +-
.../pom.xml | 64 ++++
.../test/java/junit44/environment/Basic01Test.java | 26 ++
.../test/java/junit44/environment/Basic02Test.java | 26 ++
.../test/java/junit44/environment/Basic03Test.java | 26 ++
.../test/java/junit44/environment/Basic04Test.java | 26 ++
.../test/java/junit44/environment/Basic05Test.java | 26 ++
.../test/java/junit44/environment/Basic06Test.java | 26 ++
.../test/java/junit44/environment/Basic07Test.java | 26 ++
.../test/java/junit44/environment/Basic08Test.java | 26 ++
.../test/java/junit44/environment/Basic09Test.java | 26 ++
.../test/java/junit44/environment/Basic10Test.java | 26 ++
.../surefire-946-self-destruct-plugin/pom.xml | 51 +++
.../surefire/selfdestruct/SelfDestructMojo.java | 142 ++++++++
24 files changed, 761 insertions(+), 211 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/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 892c6a9..164f8c7 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
@@ -86,7 +86,7 @@ public class ForkStarter
* Closes an InputStream
*/
private final class InputStreamCloser
- extends Thread
+ implements Runnable
{
private InputStream testProvidingInputStream;
@@ -95,8 +95,7 @@ public class ForkStarter
this.testProvidingInputStream = testProvidingInputStream;
}
- @Override
- public void run()
+ public synchronized void run()
{
if ( testProvidingInputStream != null )
{
@@ -108,6 +107,7 @@ public class ForkStarter
{
// ignore
}
+ testProvidingInputStream = null;
}
}
}
@@ -412,16 +412,18 @@ public class ForkStarter
startupConfiguration.getClassLoaderConfiguration(),
startupConfiguration.isShadefire(), threadNumber );
- final InputStreamCloser inputStreamCloserHook;
+ final InputStreamCloser inputStreamCloser;
+ final Thread inputStreamCloserHook;
if ( testProvidingInputStream != null )
{
testProvidingInputStream.setFlushReceiverProvider( cli );
-
- inputStreamCloserHook = new InputStreamCloser( testProvidingInputStream );
+ inputStreamCloser = new InputStreamCloser( testProvidingInputStream );
+ inputStreamCloserHook = new Thread( inputStreamCloser );
addShutDownHook( inputStreamCloserHook );
}
else
{
+ inputStreamCloser = null;
inputStreamCloserHook = null;
}
@@ -446,7 +448,7 @@ public class ForkStarter
final int timeout = forkedProcessTimeoutInSeconds > 0 ? forkedProcessTimeoutInSeconds : 0;
final int result =
CommandLineUtils.executeCommandLine( cli, testProvidingInputStream, threadedStreamConsumer,
- threadedStreamConsumer, timeout );
+ threadedStreamConsumer, timeout, inputStreamCloser );
if ( result != RunResult.SUCCESS )
{
throw new SurefireBooterForkException( "Error occurred in starting fork, check output in log" );
@@ -465,10 +467,10 @@ public class ForkStarter
finally
{
threadedStreamConsumer.close();
- if ( inputStreamCloserHook != null )
+ if ( inputStreamCloser != null )
{
+ inputStreamCloser.run();
removeShutdownHook( inputStreamCloserHook );
- inputStreamCloserHook.run();
}
if ( runResult == null )
{
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
index 4f5f6a4..df14d35 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
@@ -1,125 +1,125 @@
-package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
-
-/*
- * 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.IOException;
-import java.io.InputStream;
-import java.util.Queue;
-import java.util.concurrent.Semaphore;
-
-/**
- * An {@link InputStream} that, when read, provides test class names out of a queue.
- * <p/>
- * The Stream provides only one test at a time, but only after {@link #provideNewTest()} has been invoked.
- * <p/>
- * After providing each test class name, followed by a newline character, a flush is performed on the
- * {@link FlushReceiver} provided by the {@link FlushReceiverProvider} that can be set using
- * {@link #setFlushReceiverProvider(FlushReceiverProvider)}.
- *
- * @author Andreas Gudian
- */
-public class TestProvidingInputStream
- extends InputStream
-{
- private final Queue<String> testItemQueue;
-
- private byte[] currentBuffer;
-
- private int currentPos;
-
- private Semaphore semaphore = new Semaphore( 0 );
-
- private FlushReceiverProvider flushReceiverProvider;
-
- private volatile boolean closed = false;
-
- /**
- * C'tor
- *
- * @param testItemQueue source of the tests to be read from this stream
- */
- public TestProvidingInputStream( Queue<String> testItemQueue )
- {
- this.testItemQueue = testItemQueue;
- }
-
- /**
- * @param flushReceiverProvider the provider for a flush receiver.
- */
- public void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider )
- {
- this.flushReceiverProvider = flushReceiverProvider;
- }
-
- @Override
- public synchronized int read()
- throws IOException
- {
- if ( null == currentBuffer )
- {
- if ( null != flushReceiverProvider && null != flushReceiverProvider.getFlushReceiver() )
- {
- flushReceiverProvider.getFlushReceiver().flush();
- }
-
- semaphore.acquireUninterruptibly();
-
- if ( closed )
- {
- return -1;
- }
-
- String currentElement = testItemQueue.poll();
- if ( null != currentElement )
- {
- currentBuffer = currentElement.getBytes();
- currentPos = 0;
- }
- else
- {
- return -1;
- }
- }
-
- if ( currentPos < currentBuffer.length )
- {
- return ( currentBuffer[currentPos++] & 0xff );
- }
- else
- {
- currentBuffer = null;
- return ( '\n' & 0xff );
- }
- }
-
- /**
- * Signal that a new test is to be provided.
- */
- public void provideNewTest()
- {
- semaphore.release();
- }
-
- public void close()
- {
- closed = true;
- semaphore.release();
- }
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
+
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.util.Queue;
+import java.util.concurrent.Semaphore;
+
+/**
+ * An {@link InputStream} that, when read, provides test class names out of a queue.
+ * <p/>
+ * The Stream provides only one test at a time, but only after {@link #provideNewTest()} has been invoked.
+ * <p/>
+ * After providing each test class name, followed by a newline character, a flush is performed on the
+ * {@link FlushReceiver} provided by the {@link FlushReceiverProvider} that can be set using
+ * {@link #setFlushReceiverProvider(FlushReceiverProvider)}.
+ *
+ * @author Andreas Gudian
+ */
+public class TestProvidingInputStream
+ extends InputStream
+{
+ private final Queue<String> testItemQueue;
+
+ private byte[] currentBuffer;
+
+ private int currentPos;
+
+ private Semaphore semaphore = new Semaphore( 0 );
+
+ private FlushReceiverProvider flushReceiverProvider;
+
+ private boolean closed = false;
+
+ /**
+ * C'tor
+ *
+ * @param testItemQueue source of the tests to be read from this stream
+ */
+ public TestProvidingInputStream( Queue<String> testItemQueue )
+ {
+ this.testItemQueue = testItemQueue;
+ }
+
+ /**
+ * @param flushReceiverProvider the provider for a flush receiver.
+ */
+ public void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider )
+ {
+ this.flushReceiverProvider = flushReceiverProvider;
+ }
+
+ @Override
+ public synchronized int read()
+ throws IOException
+ {
+ if ( null == currentBuffer )
+ {
+ if ( null != flushReceiverProvider && null != flushReceiverProvider.getFlushReceiver() )
+ {
+ flushReceiverProvider.getFlushReceiver().flush();
+ }
+
+ semaphore.acquireUninterruptibly();
+
+ if ( closed )
+ {
+ return -1;
+ }
+
+ String currentElement = testItemQueue.poll();
+ if ( null != currentElement )
+ {
+ currentBuffer = currentElement.getBytes();
+ currentPos = 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ if ( currentPos < currentBuffer.length )
+ {
+ return ( currentBuffer[currentPos++] & 0xff );
+ }
+ else
+ {
+ currentBuffer = null;
+ return ( '\n' & 0xff );
+ }
+ }
+
+ /**
+ * Signal that a new test is to be provided.
+ */
+ public void provideNewTest()
+ {
+ semaphore.release();
+ }
+
+ public void close()
+ {
+ closed = true;
+ semaphore.release();
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/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 932f148..fa2f41d 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
@@ -156,11 +156,7 @@ public class ForkClient
case ForkingRunListener.BOOTERCODE_ERROR:
errorInFork = deserializeStackStraceWriter( new StringTokenizer( remaining, "," ) );
break;
- case ForkingRunListener.BOOTERCODE_CRASH:
- closeTestProvidingInputStream();
- break;
case ForkingRunListener.BOOTERCODE_BYE:
- closeTestProvidingInputStream();
saidGoodBye = true;
break;
default:
@@ -177,14 +173,6 @@ public class ForkClient
}
}
- private void closeTestProvidingInputStream()
- {
- if ( null != testProvidingInputStream )
- {
- testProvidingInputStream.close();
- }
- }
-
public void consumeMultiLineContent( String s )
throws IOException
{
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0fda14a..22ab636 100644
--- a/pom.xml
+++ b/pom.xml
@@ -241,7 +241,7 @@
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-utils</artifactId>
- <version>0.2</version>
+ <version>0.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index 6ec7223..fa4e9cf 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -69,8 +69,6 @@ public class ForkingRunListener
public static final byte BOOTERCODE_TEST_SKIPPED = (byte) '9';
- public static final byte BOOTERCODE_CRASH = (byte) 'C';
-
public static final byte BOOTERCODE_TEST_ASSUMPTIONFAILURE = (byte) 'G';
public static final byte BOOTERCODE_CONSOLE = (byte) 'H';
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/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 5f711f4..c06297a 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
@@ -21,7 +21,6 @@ package org.apache.maven.surefire.booter;
import java.io.File;
import java.io.FileInputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
@@ -36,7 +35,7 @@ import org.apache.maven.surefire.util.LazyTestsToRun;
* <p/>
* Deals with deserialization of the booter wire-level protocol
* <p/>
- *
+ *
* @author Jason van Zyl
* @author Emmanuel Venisse
* @author Kristian Rosenvold
@@ -44,58 +43,10 @@ import org.apache.maven.surefire.util.LazyTestsToRun;
public class ForkedBooter
{
- private final static long SYSTEM_EXIT_TIMEOUT = 30 * 1000;
-
- private final static String GOODBYE_MESSAGE = ( (char) ForkingRunListener.BOOTERCODE_BYE ) + ",0,BYE!";
-
- private final static String CRASH_MESSAGE = ( (char) ForkingRunListener.BOOTERCODE_CRASH ) + ",0,F!";
-
- private static boolean sayGoodbye = false;
-
- private static final class GoodbyeReporterAndStdStreamCloser
- implements Runnable
- {
-
- private InputStream originalIn;
-
- private PrintStream originalOut;
-
- public GoodbyeReporterAndStdStreamCloser()
- {
- this.originalIn = System.in;
- this.originalOut = System.out;
- }
-
- public void run()
- {
- try
- {
- originalIn.close();
- }
- catch ( IOException ignore )
- {
- }
-
- if ( sayGoodbye )
- {
- originalOut.println( GOODBYE_MESSAGE );
- }
- else
- {
- originalOut.println( CRASH_MESSAGE );
- }
-
- originalOut.flush();
- originalOut.close();
- }
- }
-
/**
* This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and
- * then calls the Surefire class' run method.
- * <p/>
- * The system exit code will be 1 if an exception is thrown.
- *
+ * then calls the Surefire class' run method. <p/> The system exit code will be 1 if an exception is thrown.
+ *
* @param args Commandline arguments
* @throws Throwable Upon throwables
*/
@@ -103,9 +54,6 @@ public class ForkedBooter
throws Throwable
{
final PrintStream originalOut = System.out;
-
- Runtime.getRuntime().addShutdownHook( new Thread( new GoodbyeReporterAndStdStreamCloser() ) );
-
try
{
if ( args.length > 1 )
@@ -123,8 +71,8 @@ public class ForkedBooter
boolean readTestsFromInputStream = providerConfiguration.isReadTestsFromInStream();
final ClasspathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();
- final ClassLoader testClassLoader =
- classpathConfiguration.createForkingTestClassLoader( startupConfiguration.isManifestOnlyJarRequestedAndUsable() );
+ final ClassLoader testClassLoader = classpathConfiguration.createForkingTestClassLoader(
+ startupConfiguration.isManifestOnlyJarRequestedAndUsable() );
startupConfiguration.writeSurefireTestClasspathProperty();
@@ -144,7 +92,8 @@ public class ForkedBooter
try
{
- runSuitesInProcess( testSet, testClassLoader, startupConfiguration, providerConfiguration, originalOut );
+ runSuitesInProcess( testSet, testClassLoader, startupConfiguration, providerConfiguration,
+ originalOut );
}
catch ( InvocationTargetException t )
{
@@ -162,8 +111,10 @@ public class ForkedBooter
ForkingRunListener.encode( stringBuffer, stackTraceWriter, false );
originalOut.println( ( (char) ForkingRunListener.BOOTERCODE_ERROR ) + ",0," + stringBuffer.toString() );
}
-
- sayGoodbye = true;
+ // Say bye.
+ originalOut.println( ( (char) ForkingRunListener.BOOTERCODE_BYE ) + ",0,BYE!" );
+ originalOut.flush();
+ // noinspection CallToSystemExit
exit( 0 );
}
catch ( Throwable t )
@@ -176,12 +127,15 @@ public class ForkedBooter
}
}
+ private final static long SYSTEM_EXIT_TIMEOUT = 30 * 1000;
+
private static void exit( final int returnCode )
{
launchLastDitchDaemonShutdownThread( returnCode );
System.exit( returnCode );
}
+
private static RunResult runSuitesInProcess( Object testSet, ClassLoader testsClassLoader,
StartupConfiguration startupConfiguration,
ProviderConfiguration providerConfiguration,
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/CrashDetectionIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/CrashDetectionIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/CrashDetectionIT.java
index 31e3e01..88e50f6 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/CrashDetectionIT.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/CrashDetectionIT.java
@@ -36,4 +36,9 @@ public class CrashDetectionIT
{
unpack( "crash-detection" ).forkOncePerThread().threadCount( 1 ).maven().withFailure().executeTest();
}
+
+ public void testHardCrashInReusableFork()
+ {
+ unpack( "crash-detection" ).forkOncePerThread().threadCount( 1 ).addGoal( "-DkillHard=true" ).maven().withFailure().executeTest();
+ }
}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
index bbf910c..cc745de 100755
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java
@@ -377,6 +377,10 @@ public class MavenLauncher
return validator;
}
+ public void setForkJvm( boolean forkJvm ) {
+ getVerifier().setForkJvm( forkJvm );
+ }
+
private Verifier getVerifier()
{
if ( verifier == null )
@@ -392,7 +396,7 @@ public class MavenLauncher
}
return verifier;
}
-
+
private File simpleExtractResources( Class<?> cl, String resourcePath )
{
if ( !resourcePath.startsWith( "/" ) )
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
index 84ea8b9..135216e 100755
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
@@ -370,10 +370,15 @@ public class SurefireLauncher
return "org.apache.maven.plugins:maven-surefire-report-plugin:" + getSurefireVersion() + ":" + goal;
}
-
public SurefireLauncher setTestToRun( String basicTest )
{
mavenLauncher.sysProp( "test", basicTest );
return this;
}
+
+ public SurefireLauncher setForkJvm( boolean forkJvm )
+ {
+ mavenLauncher.setForkJvm( true );
+ return this;
+ }
}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
new file mode 100644
index 0000000..60bcfb7
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire946KillMainProcessInReusableForkIT.java
@@ -0,0 +1,71 @@
+package org.apache.maven.surefire.its.jiras;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class Surefire946KillMainProcessInReusableForkIT
+ extends SurefireJUnit4IntegrationTestCase
+{
+
+ // there are 10 test classes that each would wait 2 seconds.
+ private static final int TEST_SLEEP_TIME = 2000;
+
+ @BeforeClass
+ public static void installSelfdestructPlugin()
+ throws Exception
+ {
+ unpack( Surefire946KillMainProcessInReusableForkIT.class, "surefire-946-self-destruct-plugin", "plugin" ).executeInstall();
+ }
+
+ @Test( timeout = 30000 )
+ public void testHalt()
+ throws Exception
+ {
+ doTest( "halt" );
+ }
+
+ @Test( timeout = 30000 )
+ public void testExit()
+ throws Exception
+ {
+ doTest( "exit" );
+ }
+
+ @Test( timeout = 30000 )
+ public void testInterrupt()
+ throws Exception
+ {
+ doTest( "interrupt" );
+ }
+
+ private void doTest( String method )
+ {
+ unpack( "surefire-946-killMainProcessInReusableFork" )
+ .sysProp( "selfdestruct.timeoutInMillis", "5000" )
+ .sysProp( "selfdestruct.method", method )
+ .sysProp( "testSleepTime", String.valueOf( TEST_SLEEP_TIME ) )
+ .addGoal( "org.apache.maven.plugins.surefire:maven-selfdestruct-plugin:selfdestruct" )
+ .setForkJvm( true )
+ .forkOncePerThread().threadCount( 1 ).maven().withFailure().executeTest();
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/crash-detection/src/test/java/junit44/environment/BasicTest.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/crash-detection/src/test/java/junit44/environment/BasicTest.java b/surefire-integration-tests/src/test/resources/crash-detection/src/test/java/junit44/environment/BasicTest.java
index d6f0155..c2157dc 100644
--- a/surefire-integration-tests/src/test/resources/crash-detection/src/test/java/junit44/environment/BasicTest.java
+++ b/surefire-integration-tests/src/test/resources/crash-detection/src/test/java/junit44/environment/BasicTest.java
@@ -15,7 +15,13 @@ public class BasicTest
@AfterClass
public static void killTheVm(){
- System.exit( 0 );
+ if ( Boolean.getBoolean( "killHard" ))
+ {
+ Runtime.getRuntime().halt( 0 );
+ }
+ else {
+ System.exit( 0 );
+ }
}
}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
new file mode 100644
index 0000000..eb0fe59
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>surefire-946</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Tests killing the main maven process when using reusable forks</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>maven-selfdestruct-plugin</artifactId>
+ <version>0.1</version>
+ <configuration>
+ <timeoutInMillis>${selfdestruct.timeoutInMillis}</timeoutInMillis>
+ <method>${selfdestruct.method}</method>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
new file mode 100644
index 0000000..efc294f
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic01Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic01Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
new file mode 100644
index 0000000..6bc29c7
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic02Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic02Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
new file mode 100644
index 0000000..6d4941b
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic03Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic03Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
new file mode 100644
index 0000000..d3b947c
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic04Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic04Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
new file mode 100644
index 0000000..a3b604e
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic05Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic05Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
new file mode 100644
index 0000000..ea5b951
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic06Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic06Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
new file mode 100644
index 0000000..715bc93
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic07Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic07Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
new file mode 100644
index 0000000..fbb8e00
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic08Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic08Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
new file mode 100644
index 0000000..89fb37b
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic09Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic09Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
new file mode 100644
index 0000000..e54edf0
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-killMainProcessInReusableFork/src/test/java/junit44/environment/Basic10Test.java
@@ -0,0 +1,26 @@
+package junit44.environment;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class Basic10Test
+{
+
+ @Test
+ public void testNothing()
+ {
+ }
+
+ @AfterClass
+ public static void waitSomeTimeAround()
+ {
+ try
+ {
+ Thread.sleep( Integer.getInteger( "testSleepTime", 2000 ) );
+ }
+ catch ( InterruptedException ignored )
+ {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/pom.xml b/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
new file mode 100644
index 0000000..91823a7
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/pom.xml
@@ -0,0 +1,51 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>maven-selfdestruct-plugin</artifactId>
+ <version>0.1</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>maven-selfdestruct-plugin Maven Plugin</name>
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <goalPrefix>maven-selfdestruct-plugin</goalPrefix>
+ </configuration>
+ <executions>
+ <execution>
+ <id>generated-helpmojo</id>
+ <goals>
+ <goal>helpmojo</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/463f37b3/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/src/main/java/org/apache/maven/plugins/surefire/selfdestruct/SelfDestructMojo.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/src/main/java/org/apache/maven/plugins/surefire/selfdestruct/SelfDestructMojo.java b/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/src/main/java/org/apache/maven/plugins/surefire/selfdestruct/SelfDestructMojo.java
new file mode 100644
index 0000000..33cd588
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/surefire-946-self-destruct-plugin/src/main/java/org/apache/maven/plugins/surefire/selfdestruct/SelfDestructMojo.java
@@ -0,0 +1,142 @@
+package org.apache.maven.plugins.surefire.selfdestruct;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ * Goal which terminates the maven process it is executed in after a timeout.
+ *
+ * @goal selfdestruct
+ * @phase test
+ */
+public class SelfDestructMojo
+ extends AbstractMojo
+{
+ private enum DestructMethod
+ {
+ exit, halt, interrupt;
+ }
+
+ /**
+ * Timeout in milliseconds
+ *
+ * @parameter
+ */
+ private long timeoutInMillis = 0;
+
+ /**
+ * Method of self-destruction: 'exit' will use System.exit (default), 'halt' will use Runtime.halt, 'interrupt' will
+ * try to call 'taskkill' (windows) or 'kill -INT' (others)
+ *
+ * @parameter
+ */
+ private String method = "exit";
+
+ public void execute()
+ throws MojoExecutionException
+ {
+
+ DestructMethod destructMethod = DestructMethod.valueOf( method );
+
+ if ( timeoutInMillis > 0 )
+ {
+ getLog().warn( "Self-Destruct in " + timeoutInMillis + " millis using " + destructMethod );
+ Timer timer = new Timer( "", true );
+ timer.schedule( new SelfDestructionTask( destructMethod ), timeoutInMillis );
+ }
+ else
+ {
+ new SelfDestructionTask( destructMethod ).run();
+ }
+ }
+
+ private void selfDestruct( DestructMethod destructMethod )
+ {
+ getLog().warn( "Self-Destructing NOW." );
+ switch ( destructMethod )
+ {
+ case exit:
+ System.exit( 1 );
+ case halt:
+ Runtime.getRuntime().halt( 1 );
+ case interrupt:
+ String name = ManagementFactory.getRuntimeMXBean().getName();
+ int indexOfAt = name.indexOf( '@' );
+ if ( indexOfAt > 0 )
+ {
+ String pid = name.substring( 0, indexOfAt );
+ getLog().warn( "Going to kill process with PID " + pid );
+
+ List<String> args = new ArrayList<String>();
+ if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
+ {
+ args.add( "taskkill" );
+ args.add( "/PID" );
+ }
+ else
+ {
+ args.add( "kill" );
+ args.add( "-INT" );
+ }
+ args.add( pid );
+
+ try
+ {
+ new ProcessBuilder( args ).start();
+ }
+ catch ( IOException e )
+ {
+ getLog().error( "Unable to spawn process. Killing with System.exit.", e );
+ }
+ }
+ else
+ {
+ getLog().warn( "Unable to determine my PID... Using System.exit" );
+ }
+ }
+
+ System.exit( 1 );
+ }
+
+ private class SelfDestructionTask
+ extends TimerTask
+ {
+
+ private DestructMethod destructMethod;
+
+ public SelfDestructionTask( DestructMethod destructMethod )
+ {
+ this.destructMethod = destructMethod;
+ }
+
+ @Override
+ public void run()
+ {
+ selfDestruct( destructMethod );
+ }
+
+ }
+}