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/02/14 18:45:53 UTC
git commit: [SUREFIRE-956] make forkNumber unique among concurrent
surefire-executions in a parallel maven build
Updated Branches:
refs/heads/master 8b5f86cab -> 0cd869cce
[SUREFIRE-956] make forkNumber unique among concurrent surefire-executions in a parallel maven build
Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/0cd869cc
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/0cd869cc
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/0cd869cc
Branch: refs/heads/master
Commit: 0cd869ccec8dadb1c8b89baf8e8495819c236720
Parents: 8b5f86c
Author: Andreas Gudian <an...@gmail.com>
Authored: Tue Feb 5 22:01:03 2013 +0100
Committer: Kristian Rosenvold <kr...@apache.org>
Committed: Thu Feb 14 18:45:36 2013 +0100
----------------------------------------------------------------------
.../plugin/surefire/AbstractSurefireMojo.java | 4 +-
.../surefire/booterclient/ForkNumberBucket.java | 87 ++++++++
.../plugin/surefire/booterclient/ForkStarter.java | 57 ++----
.../fork-options-and-parallel-execution.apt.vm | 27 ++-
.../org/apache/maven/surefire/its/ForkModeIT.java | 24 +-
.../maven/surefire/its/ForkModeMultiModuleIT.java | 156 +++++++++++++++
.../surefire/its/fixture/OutputValidator.java | 6 +
.../fork-mode-multimodule/module-a/pom.xml | 36 ++++
.../module-a/src/test/java/forkMode/Test1.java | 48 +++++
.../module-a/src/test/java/forkMode/Test2.java | 17 ++
.../module-a/src/test/java/forkMode/Test3.java | 15 ++
.../fork-mode-multimodule/module-b/pom.xml | 36 ++++
.../module-b/src/test/java/forkMode/Test1.java | 48 +++++
.../module-b/src/test/java/forkMode/Test2.java | 17 ++
.../module-b/src/test/java/forkMode/Test3.java | 15 ++
.../test/resources/fork-mode-multimodule/pom.xml | 69 +++++++
16 files changed, 608 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 3b5af70..d97848d 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -451,7 +451,9 @@ public abstract class AbstractSurefireMojo
* Example values: "1.5C", "4"<br/>
* <br/>
* The system properties and the <code>argLine</code> of the forked processes may contain the place holder string <code>${surefire.forkNumber}</code>,
- * which is replaced with a fixed number for each of the parallel forks, ranging from <code>1</code> to the effective value of <code>forkCount</code>.
+ * which is replaced with a fixed number for each of the parallel forks, ranging from <code>1</code> to the effective value of <code>forkCount</code>
+ * times the maximum number of parallel Surefire executions in maven parallel builds, i.e. the effective value of the <code>-T</code> command line
+ * argument of maven core.
*
* @since 2.14
*/
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkNumberBucket.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkNumberBucket.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkNumberBucket.java
new file mode 100644
index 0000000..c107982
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkNumberBucket.java
@@ -0,0 +1,87 @@
+package org.apache.maven.plugin.surefire.booterclient;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A bucket from which fork numbers can be drawn. Any drawn number needs to be returned to the bucket, in order to keep
+ * the range of provided values delivered as small as possible.
+ *
+ * @author Andreas Gudian
+ */
+public class ForkNumberBucket
+{
+
+ private static final ForkNumberBucket INSTANCE = new ForkNumberBucket();
+
+ private Queue<Integer> qFree = new ConcurrentLinkedQueue<Integer>();
+
+ private AtomicInteger highWaterMark = new AtomicInteger( 1 );
+
+ /**
+ * Non-public constructor
+ */
+ protected ForkNumberBucket()
+ {
+ }
+
+ /**
+ * @return a fork number that is not currently in use. The value must be returned to the bucket using
+ * {@link #returnNumber(int)}.
+ */
+ public static int drawNumber()
+ {
+ return getInstance()._drawNumber();
+ }
+
+ /**
+ * @param number the number to return to the bucket so that it can be reused.
+ */
+ public static void returnNumber( int number )
+ {
+ getInstance()._returnNumber( number );
+ }
+
+ /**
+ * @return a singleton instance
+ */
+ private static ForkNumberBucket getInstance()
+ {
+ return INSTANCE;
+ }
+
+ /**
+ * @return a fork number that is not currently in use. The value must be returned to the bucket using
+ * {@link #returnNumber(int)}.
+ */
+ protected int _drawNumber()
+ {
+ Integer nextFree = qFree.poll();
+
+ if ( null == nextFree )
+ {
+ return highWaterMark.getAndIncrement();
+ }
+ else
+ {
+ return nextFree.intValue();
+ }
+ }
+
+ /**
+ * @return the highest number that has been drawn
+ */
+ protected int getHighestDrawnNumber()
+ {
+ return highWaterMark.get() - 1;
+ }
+
+ /**
+ * @param number the number to return to the bucket so that it can be reused.
+ */
+ protected void _returnNumber( int number )
+ {
+ qFree.add( Integer.valueOf( number ) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/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 a8da513..8dd43da 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
@@ -36,7 +36,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
import org.apache.maven.plugin.surefire.CommonReflector;
@@ -126,17 +125,6 @@ public class ForkStarter
private static volatile int systemPropertiesFileCounter = 0;
- private final ThreadLocal<Integer> forkNumber = new ThreadLocal<Integer>()
- {
- private final AtomicInteger nextforkNumber = new AtomicInteger( 1 );
-
- @Override
- protected Integer initialValue()
- {
- return nextforkNumber.getAndIncrement();
- }
- };
-
public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
ForkConfiguration forkConfiguration, int forkedProcessTimeoutInSeconds,
StartupReportConfiguration startupReportConfiguration )
@@ -162,13 +150,9 @@ public class ForkStarter
final ForkClient forkClient =
new ForkClient( defaultReporterFactory, startupReportConfiguration.getTestVmSystemProperties() );
result =
- fork( null, new PropertiesWrapper( providerProperties ), forkClient, effectiveSystemProperties, 1,
+ fork( null, new PropertiesWrapper( providerProperties ), forkClient, effectiveSystemProperties,
null );
}
- else if ( isForkAlways() )
- {
- result = runSuitesForkPerTestSet( effectiveSystemProperties, 1 );
- }
else
{
if ( forkConfiguration.isReuseForks() )
@@ -188,11 +172,6 @@ public class ForkStarter
return result;
}
- private boolean isForkAlways()
- {
- return !forkConfiguration.isReuseForks() && 1 == forkConfiguration.getForkCount();
- }
-
private boolean isForkOnce()
{
return forkConfiguration.isReuseForks() && 1 == forkConfiguration.getForkCount();
@@ -226,8 +205,6 @@ public class ForkStarter
for ( int forkNum = 0; forkNum < forkCount && forkNum < suites.size(); forkNum++ )
{
- final int finalForkNumber = forkNum + 1;
-
Callable<RunResult> pf = new Callable<RunResult>()
{
public RunResult call()
@@ -241,7 +218,7 @@ public class ForkStarter
testProvidingInputStream );
return fork( null, new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
- forkClient, effectiveSystemProperties, finalForkNumber, testProvidingInputStream );
+ forkClient, effectiveSystemProperties, testProvidingInputStream );
}
};
@@ -302,19 +279,11 @@ public class ForkStarter
public RunResult call()
throws Exception
{
- int thisThreadsForkNumber = forkNumber.get();
- if ( thisThreadsForkNumber > forkCount )
- {
- // this would be a bug in the ThreadPoolExecutor
- throw new IllegalStateException( "More threads than " + forkCount
- + " have been created by the ThreadPoolExecutor." );
- }
-
ForkClient forkClient =
new ForkClient( defaultReporterFactory,
startupReportConfiguration.getTestVmSystemProperties() );
return fork( testSet, new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
- forkClient, effectiveSystemProperties, thisThreadsForkNumber, null );
+ forkClient, effectiveSystemProperties, null );
}
};
results.add( executorService.submit( pf ) );
@@ -370,6 +339,23 @@ public class ForkStarter
}
private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
+ SurefireProperties effectiveSystemProperties,
+ TestProvidingInputStream testProvidingInputStream )
+ throws SurefireBooterForkException
+ {
+ int forkNumber = ForkNumberBucket.drawNumber();
+ try
+ {
+ return fork( testSet, providerProperties, forkClient, effectiveSystemProperties, forkNumber,
+ testProvidingInputStream );
+ }
+ finally
+ {
+ ForkNumberBucket.returnNumber( forkNumber );
+ }
+ }
+
+ private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
SurefireProperties effectiveSystemProperties, int forkNumber,
TestProvidingInputStream testProvidingInputStream )
throws SurefireBooterForkException
@@ -387,8 +373,7 @@ public class ForkStarter
if ( effectiveSystemProperties != null )
{
SurefireProperties filteredProperties =
- AbstractSurefireMojo.createCopyAndReplaceForkNumPlaceholder( effectiveSystemProperties,
- forkNumber );
+ AbstractSurefireMojo.createCopyAndReplaceForkNumPlaceholder( effectiveSystemProperties, forkNumber );
systPropsFile =
SystemPropertyManager.writePropertiesFile( filteredProperties,
forkConfiguration.getTempDirectory(), "surefire_"
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm b/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
index 444cbd1..5e47b0d 100644
--- a/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/fork-options-and-parallel-execution.apt.vm
@@ -62,6 +62,12 @@ Fork Options and Parallel Test Execution
<<<forkCount>>> to a value higher than 1. The next section covers the details
about this and the related <<<reuseForks>>> property.
+* Parallel Surefire Execution in Multi-Module Maven Parallel Build
+
+ Maven core allows building modules of multi-module projects in parallel with
+ the command line option <<<-T>>>. This <multiplies> the extent of concurrency
+ configured directly in Surefire.
+
* Forked Test Execution
The parameter <<<forkCount>>> defines the maximum number of JVM processes
@@ -92,11 +98,14 @@ Fork Options and Parallel Test Execution
specify variables and values to be added to the system properties during the
test execution.
- You can use the place holder <<<$\{surefire.forkNumber\}>>> within
- <<<argLine>>>, or within the system properties (both those specified via
- <<<mvn test -D...>>> and via <<<systemPropertyVariables>>>). Before executing
- the tests, Surefire replaces that place holder by the number of the actually
- executing process, counting from 1 to the effective value of <<<forkCount>>>.
+ You can use the place holder <<<$\{surefire.forkNumber\}>>> within
+ <<<argLine>>>, or within the system properties (both those specified via
+ <<<mvn test -D...>>> and via <<<systemPropertyVariables>>>). Before executing
+ the tests, Surefire replaces that place holder by the number of the actually
+ executing process, counting from 1 to the effective value of <<<forkCount>>>
+ times the maximum number of parallel Surefire executions in maven parallel
+ builds, i.e. the effective value of the <<<-T>>> command line argument of
+ maven core.
In case forkig is disabled (<<<forkCount=0>>>), the place holder will be
replaced with <1>.
@@ -128,6 +137,10 @@ Fork Options and Parallel Test Execution
</plugins>
+---+
+ In case of a multi module project with tests in different modules, you could
+ also use, say, <<<mvn -T 2 ...>>> to start the build, yielding values for
+ <<<$\{surefire.forkNumber\}>>> ranging from 1 to 6.
+
Imagine you execute some tests that use a JPA context, which has a notable
initial startup time. By setting <<<reuseForks=true>>>, you can reuse that
context for consecutive tests. And as many tests tend to use and access the
@@ -153,6 +166,10 @@ Fork Options and Parallel Test Execution
processes, each of the processes can then use <<<threadCount>>> threads to
execute the methods of one class in parallel.
+ Regarding the compatibility with multi-module parallel maven builds via
+ <<<-T>>>, the only limitation is that you can not use it together with
+ <<<forkCount=0>>>.
+
* Migrating the Deprecated forkMode Parameter to forkCount and reuseForks
Surefire versions prior 2.14 used the parameter <<<forkMode>>> to configure
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
index 5506caa..1077f4f 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
@@ -38,7 +38,7 @@ public class ForkModeIT
{
public void testForkModeAlways()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkAlways() );
+ String[] pids = doTest( unpack( getProject() ).setForkJvm( true ).forkAlways() );
assertDifferentPids( pids );
assertEndWith( pids, "_1_1", 3);
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
@@ -46,7 +46,7 @@ public class ForkModeIT
public void testForkModePerTest()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkPerTest() );
+ String[] pids = doTest( unpack( getProject() ).setForkJvm( true ).forkPerTest() );
assertDifferentPids( pids );
assertEndWith( pids, "_1_1", 3);
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
@@ -54,7 +54,7 @@ public class ForkModeIT
public void testForkModeNever()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkNever() );
+ String[] pids = doTest( unpack( getProject() ).forkNever() );
assertSamePids( pids );
assertEndWith( pids, "_1_1", 3);
assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] );
@@ -62,7 +62,7 @@ public class ForkModeIT
public void testForkModeNone()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkMode( "none" ) );
+ String[] pids = doTest( unpack( getProject() ).forkMode( "none" ) );
assertSamePids( pids );
assertEndWith( pids, "_1_1", 3);
assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] );
@@ -70,7 +70,7 @@ public class ForkModeIT
public void testForkModeOncePerThreadSingleThread()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkOncePerThread().threadCount( 1 ) );
+ String[] pids = doTest( unpack( getProject() ).setForkJvm( true ).forkOncePerThread().threadCount( 1 ) );
assertSamePids( pids );
assertEndWith( pids, "_1_1", 3);
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
@@ -78,14 +78,14 @@ public class ForkModeIT
public void testForkModeOncePerThreadTwoThreads()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkOncePerThread().threadCount( 2 ).addGoal( "-DsleepLength=1200" ) );
+ String[] pids = doTest( unpack( getProject() ).forkOncePerThread().threadCount( 2 ).addGoal( "-DsleepLength=1200" ) );
assertDifferentPids( pids, 2 );
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
}
public void testForkCountZero()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 0 ) );
+ String[] pids = doTest( unpack( getProject() ).forkCount( 0 ) );
assertSamePids( pids );
assertEndWith( pids, "_1_1", 3);
assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] );
@@ -93,7 +93,7 @@ public class ForkModeIT
public void testForkCountOneNoReuse()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 1 ).reuseForks( false ) );
+ String[] pids = doTest( unpack( getProject() ).setForkJvm( true ).forkCount( 1 ).reuseForks( false ) );
assertDifferentPids( pids );
assertEndWith( pids, "_1_1", 3);
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
@@ -101,7 +101,7 @@ public class ForkModeIT
public void testForkCountOneReuse()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 1 ).reuseForks( true ) );
+ String[] pids = doTest( unpack( getProject() ).setForkJvm( true ).forkCount( 1 ).reuseForks( true ) );
assertSamePids( pids );
assertEndWith( pids, "_1_1", 3);
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
@@ -109,14 +109,14 @@ public class ForkModeIT
public void testForkCountTwoNoReuse()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 2 ).reuseForks( false ).addGoal( "-DsleepLength=1200" ) );
+ String[] pids = doTest( unpack( getProject() ).forkCount( 2 ).reuseForks( false ).addGoal( "-DsleepLength=1200" ) );
assertDifferentPids( pids );
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
}
public void testForkCountTwoReuse()
{
- String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 2 ).reuseForks( true ).addGoal( "-DsleepLength=1200" ) );
+ String[] pids = doTest( unpack( getProject() ).forkCount( 2 ).reuseForks( true ).addGoal( "-DsleepLength=1200" ) );
assertDifferentPids( pids, 2 );
assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) );
}
@@ -178,7 +178,7 @@ public class ForkModeIT
private String[] doTest( SurefireLauncher forkMode )
{
forkMode.sysProp( "testProperty", "testValue_${surefire.threadNumber}_${surefire.forkNumber}" );
- final OutputValidator outputValidator = forkMode.executeTest();
+ final OutputValidator outputValidator = forkMode.debugLogging().executeTest();
outputValidator.verifyErrorFreeLog().assertTestSuiteResults( 3, 0, 0, 0 );
String[] pids = new String[3];
for ( int i = 1; i <= pids.length; i++ )
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeMultiModuleIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeMultiModuleIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeMultiModuleIT.java
new file mode 100644
index 0000000..6d972ad
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeMultiModuleIT.java
@@ -0,0 +1,156 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.surefire.its.fixture.HelperAssertions;
+import org.apache.maven.surefire.its.fixture.OutputValidator;
+import org.apache.maven.surefire.its.fixture.SurefireIntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.apache.maven.surefire.its.fixture.TestFile;
+
+/**
+ * Test forkMode in a multi module project with parallel maven builds
+ *
+ * @author Andreas Gudian
+ */
+public class ForkModeMultiModuleIT
+ extends SurefireIntegrationTestCase
+{
+ public void testForkCountOneNoReuse()
+ {
+ List<String> pids = doTest( unpack( getProject() ).forkCount( 1 ).reuseForks( false ) );
+ assertAllDifferentPids( pids );
+ int matchesOne = countSuffixMatches( pids, "_1_1");
+ int matchesTwo = countSuffixMatches( pids, "_2_2" );
+ assertTrue( "At least one fork had forkNumber 1", matchesOne >= 1 );
+ assertTrue( "At least one fork had forkNumber 2", matchesTwo >= 1 );
+ assertEquals( "No other forkNumbers than 1 and 2 have been used", 6, matchesOne + matchesTwo);
+ }
+
+ public void testForkCountOneReuse()
+ {
+ List<String> pids = doTest( unpack( getProject() ).forkCount( 1 ).reuseForks( true ) );
+ assertDifferentPids( pids, 2 );
+ assertEndWith( pids, "_1_1", 3 );
+ assertEndWith( pids, "_2_2", 3 );
+ }
+
+ public void testForkCountTwoNoReuse()
+ {
+ List<String> pids = doTest( unpack( getProject() ).forkCount( 2 ).reuseForks( false ) );
+ assertAllDifferentPids( pids );
+ int matchesOne = countSuffixMatches( pids, "_1_1");
+ int matchesTwo = countSuffixMatches( pids, "_2_2" );
+ int matchesThree = countSuffixMatches( pids, "_3_3");
+ int matchesFour = countSuffixMatches( pids, "_4_4" );
+ assertTrue( "At least one fork had forkNumber 1", matchesOne >= 1 );
+ assertTrue( "At least one fork had forkNumber 2", matchesTwo >= 1 );
+ assertTrue( "At least one fork had forkNumber 3", matchesThree >= 1 );
+ assertTrue( "At least one fork had forkNumber 4", matchesFour >= 1 );
+ assertEquals( "No other forkNumbers than 1, 2, 3, or 4 have been used", 6, matchesOne + matchesTwo + matchesThree + matchesFour );
+ }
+
+ public void testForkCountTwoReuse()
+ {
+ List<String> pids =
+ doTest( unpack( getProject() ).forkCount( 2 ).reuseForks( true ) );
+ assertDifferentPids( pids, 4 );
+
+ int matchesOne = countSuffixMatches( pids, "_1_1");
+ int matchesTwo = countSuffixMatches( pids, "_2_2" );
+ int matchesThree = countSuffixMatches( pids, "_3_3");
+ int matchesFour = countSuffixMatches( pids, "_4_4" );
+ assertTrue( "At least one fork had forkNumber 1", matchesOne >= 1 );
+ assertTrue( "At least one fork had forkNumber 2", matchesTwo >= 1 );
+ assertTrue( "At least one fork had forkNumber 3", matchesThree >= 1 );
+ assertTrue( "At least one fork had forkNumber 4", matchesFour >= 1 );
+ assertEquals( "No other forkNumbers than 1, 2, 3, or 4 have been used", 6, matchesOne + matchesTwo + matchesThree + matchesFour );
+ }
+
+ private void assertEndWith( List<String> pids, String suffix, int expectedMatches )
+ {
+ int matches = countSuffixMatches( pids, suffix );
+
+ assertEquals( "suffix " + suffix + " matched the correct number of pids", expectedMatches, matches );
+ }
+
+ private int countSuffixMatches( List<String> pids, String suffix )
+ {
+ int matches = 0;
+ for ( String pid : pids )
+ {
+ if ( pid.endsWith( suffix ) )
+ {
+ matches++;
+ }
+ }
+ return matches;
+ }
+
+ private void assertDifferentPids( List<String> pids, int numOfDifferentPids )
+ {
+ Set<String> pidSet = new HashSet<String>( pids );
+ assertEquals( "number of different pids is not as expected", numOfDifferentPids, pidSet.size() );
+ }
+
+ private void assertAllDifferentPids( List<String> pids )
+ {
+ assertDifferentPids( pids, pids.size() );
+ }
+
+ private List<String> doTest( SurefireLauncher forkMode )
+ {
+ forkMode.addGoal( "-T 2" );
+ forkMode.sysProp( "testProperty", "testValue_${surefire.threadNumber}_${surefire.forkNumber}" );
+ final OutputValidator outputValidator = forkMode.setForkJvm( true ).executeTest();
+ List<String> pids = new ArrayList<String>( 6 );
+ pids.addAll( validateModule( outputValidator, "module-a" ) );
+ pids.addAll( validateModule( outputValidator, "module-b" ) );
+
+ return pids;
+ }
+
+ private List<String> validateModule( OutputValidator outputValidator, String module )
+ {
+ HelperAssertions.assertTestSuiteResults( 3, 0, 0, 0, new File( outputValidator.getBaseDir(), module ) );
+
+ List<String> pids = new ArrayList<String>( 3 );
+ for ( int i = 1; i <= 3; i++ )
+ {
+ final TestFile targetFile = outputValidator.getTargetFile( module, "test" + i + "-pid" );
+ String pid = targetFile.slurpFile();
+ pids.add( pid );
+ }
+
+ return pids;
+ }
+
+ protected String getProject()
+ {
+ return "fork-mode-multimodule";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/OutputValidator.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/OutputValidator.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/OutputValidator.java
index 7208ae3..99e9a18 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/OutputValidator.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/OutputValidator.java
@@ -147,6 +147,12 @@ public class OutputValidator
return this;
}
+ public TestFile getTargetFile( String modulePath, String fileName )
+ {
+ File targetDir = getSubFile( modulePath + "/target" );
+ return new TestFile( new File( targetDir, fileName ), this );
+ }
+
public TestFile getTargetFile( String fileName )
{
File targetDir = getSubFile( "target" );
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/pom.xml b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/pom.xml
new file mode 100644
index 0000000..cbaf407
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/pom.xml
@@ -0,0 +1,36 @@
+<?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>
+
+ <parent>
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>fork-mode-multimodule</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>fork-mode-multimodule.module-a</artifactId>
+ <name>Test for forkMode Module A</name>
+
+</project>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test1.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test1.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test1.java
new file mode 100644
index 0000000..08ac31d
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test1.java
@@ -0,0 +1,48 @@
+package forkMode;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class Test1
+ extends TestCase
+{
+
+ private static final Random RANDOM = new Random();
+
+ public void test1()
+ throws IOException, InterruptedException
+ {
+ int sleepLength = Integer.valueOf( System.getProperty( "sleepLength", "1500" ));
+ Thread.sleep(sleepLength);
+ dumpPidFile( this );
+ }
+
+ public static void dumpPidFile( TestCase test )
+ throws IOException
+ {
+ String fileName = test.getName() + "-pid";
+ File target = new File( "target" ).getCanonicalFile(); // getCanonicalFile required for embedded mode
+ if ( !( target.exists() && target.isDirectory() ) )
+ {
+ target = new File( "." );
+ }
+ File pidFile = new File( target, fileName );
+ FileWriter fw = new FileWriter( pidFile );
+ // DGF little known trick... this is guaranteed to be unique to the PID
+ // In fact, it usually contains the pid and the local host name!
+ String pid = ManagementFactory.getRuntimeMXBean().getName();
+ fw.write( pid );
+ fw.write( " " );
+ fw.write( System.getProperty( "testProperty", String.valueOf( RANDOM.nextLong() ) ) );
+ fw.flush();
+ fw.close();
+ System.out.println( "Done Writing pid file" + pidFile.getAbsolutePath() );
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test2.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test2.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test2.java
new file mode 100644
index 0000000..ce30de9
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test2.java
@@ -0,0 +1,17 @@
+package forkMode;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class Test2
+ extends TestCase
+{
+
+ public void test2() throws IOException, InterruptedException {
+ int sleepLength = Integer.valueOf( System.getProperty( "sleepLength", "1500" ));
+ Thread.sleep(sleepLength);
+ Test1.dumpPidFile(this);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test3.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test3.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test3.java
new file mode 100644
index 0000000..deb9296
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-a/src/test/java/forkMode/Test3.java
@@ -0,0 +1,15 @@
+package forkMode;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class Test3
+ extends TestCase
+{
+
+ public void test3() throws IOException {
+ Test1.dumpPidFile(this);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/pom.xml b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/pom.xml
new file mode 100644
index 0000000..ba076ce
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/pom.xml
@@ -0,0 +1,36 @@
+<?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>
+
+ <parent>
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>fork-mode-multimodule</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>fork-mode-multimodule.module-b</artifactId>
+ <name>Test for forkMode Module B</name>
+
+</project>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test1.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test1.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test1.java
new file mode 100644
index 0000000..08ac31d
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test1.java
@@ -0,0 +1,48 @@
+package forkMode;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class Test1
+ extends TestCase
+{
+
+ private static final Random RANDOM = new Random();
+
+ public void test1()
+ throws IOException, InterruptedException
+ {
+ int sleepLength = Integer.valueOf( System.getProperty( "sleepLength", "1500" ));
+ Thread.sleep(sleepLength);
+ dumpPidFile( this );
+ }
+
+ public static void dumpPidFile( TestCase test )
+ throws IOException
+ {
+ String fileName = test.getName() + "-pid";
+ File target = new File( "target" ).getCanonicalFile(); // getCanonicalFile required for embedded mode
+ if ( !( target.exists() && target.isDirectory() ) )
+ {
+ target = new File( "." );
+ }
+ File pidFile = new File( target, fileName );
+ FileWriter fw = new FileWriter( pidFile );
+ // DGF little known trick... this is guaranteed to be unique to the PID
+ // In fact, it usually contains the pid and the local host name!
+ String pid = ManagementFactory.getRuntimeMXBean().getName();
+ fw.write( pid );
+ fw.write( " " );
+ fw.write( System.getProperty( "testProperty", String.valueOf( RANDOM.nextLong() ) ) );
+ fw.flush();
+ fw.close();
+ System.out.println( "Done Writing pid file" + pidFile.getAbsolutePath() );
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test2.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test2.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test2.java
new file mode 100644
index 0000000..ce30de9
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test2.java
@@ -0,0 +1,17 @@
+package forkMode;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class Test2
+ extends TestCase
+{
+
+ public void test2() throws IOException, InterruptedException {
+ int sleepLength = Integer.valueOf( System.getProperty( "sleepLength", "1500" ));
+ Thread.sleep(sleepLength);
+ Test1.dumpPidFile(this);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test3.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test3.java b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test3.java
new file mode 100644
index 0000000..deb9296
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/module-b/src/test/java/forkMode/Test3.java
@@ -0,0 +1,15 @@
+package forkMode;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class Test3
+ extends TestCase
+{
+
+ public void test3() throws IOException {
+ Test1.dumpPidFile(this);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0cd869cc/surefire-integration-tests/src/test/resources/fork-mode-multimodule/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/fork-mode-multimodule/pom.xml b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/pom.xml
new file mode 100644
index 0000000..98e073f
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/fork-mode-multimodule/pom.xml
@@ -0,0 +1,69 @@
+<?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>fork-mode-multimodule</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Test for forkMode Multimodule</name>
+
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>module-a</module>
+ <module>module-b</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <configuration>
+ <forkMode>${forkMode}</forkMode>
+ <threadCount>${threadCount}</threadCount>
+ <runOrder>alphabetical</runOrder>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>