[SUREFIRE-949] add forkCount parameter, making the inconsitent forkMode parameter deprecated.
- All defaulting works as in the previous versions, with the exception of reuseForks (introduced in the last release). It's now true by default. - forkCount supports "C" notation as in -T of maven-core Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/01f5ddbc Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/01f5ddbc Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/01f5ddbc Branch: refs/heads/master Commit: 01f5ddbcfe5db33e5518c36199ababc60228e90a Parents: 9a39962 Author: Andreas Gudian <andreas.gud...@gmail.com> Authored: Fri Jan 18 21:15:09 2013 +0100 Committer: Kristian Rosenvold <krosenv...@apache.org> Committed: Mon Jan 21 20:08:45 2013 +0100 ---------------------------------------------------------------------- .../plugin/surefire/AbstractSurefireMojo.java | 141 +++++++++-- .../surefire/booterclient/ForkConfiguration.java | 4 +- .../plugin/surefire/booterclient/ForkStarter.java | 26 ++- .../maven/plugin/surefire/SurefirePluginTest.java | 192 +++++++++------ .../org/apache/maven/surefire/its/ForkModeIT.java | 84 ++++++- .../surefire/its/fixture/SurefireLauncher.java | 18 +- 6 files changed, 337 insertions(+), 128 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/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 fd00d5f..bc8eb0b 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 @@ -329,10 +329,12 @@ public abstract class AbstractSurefireMojo protected Boolean failIfNoTests; /** + * <strong>DEPRECATED</strong> since version 2.14. Use <code>forkCount</code> and <code>reuseForks</code> instead.<br/> + * <br/> * Option to specify the forking mode. Can be "never", "once", "always", "perthread". "none" and "pertest" are also accepted - * for backwards compatibility. "always" forks for each test-class. "perthread" will create "threadCount" parallel forks, each executing one test-class, see also parameter reuseForks.<br/> + * for backwards compatibility. "always" forks for each test-class. "perthread" will create <code>threadCount</code> parallel forks, each executing one test-class, see also parameter <code>reuseForks</code>.<br/> * The system properties and the "argLine" of the forked processes may contain the place holder string <code>${surefire.threadNumber}</code>, - * which is replaced with a fixed number for each thread, ranging from 1 to "threadCount". + * which is replaced with a fixed number for each thread, ranging from 1 to <code>threadCount</code>. * * @since 2.1 */ @@ -433,8 +435,8 @@ public abstract class AbstractSurefireMojo protected String testNGArtifactName; /** - * (forkMode=perthread or TestNG/JUnit 4.7 provider) The attribute thread-count allows you to specify how many threads should be - * allocated for this execution. Only makes sense to use in conjunction with the <code>parallel</code> parameter or with forkMode=perthread. + * (TestNG/JUnit 4.7 provider) The attribute thread-count allows you to specify how many threads should be + * allocated for this execution. Only makes sense to use in conjunction with the <code>parallel</code> parameter. * * @since 2.2 */ @@ -443,13 +445,28 @@ public abstract class AbstractSurefireMojo /** - * Indicates if forks can be reused. Currently only meaningful - * when forking N parallel forks + * Option to specify the number of VMs to fork in parallel in order to execute the tests. + * When terminated with "C", the number part is multiplied with the number of CPU cores. Floating point value are only accepted together with "C". + * If set to "0", no VM is forked and all tests are executed within the main process.<br/> + * <br/> + * 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>. + * + * @since 2.14 + */ + @Parameter( property = "forkCount", defaultValue="1") + private String forkCount; + + /** + * Indicates if forked VMs can be reused. If set to "false", a new VM is forked for each test class to be executed. + * If set to "true", up to <code>forkCount</code> VMs will be forked and then reused to execute all tests. * * @since 2.13 */ - @Parameter( property = "reuseForks", defaultValue = "false" ) + @Parameter( property = "reuseForks", defaultValue = "true" ) private boolean reuseForks; /** @@ -587,12 +604,21 @@ public abstract class AbstractSurefireMojo private Toolchain toolchain; + private int effectiveForkCount = -1; + /** * The placeholder that is replaced by the executing thread's running number. The thread number * range starts with 1 + * Deprecated. */ public static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}"; + /** + * The placeholder that is replaced by the executing fork's running number. The fork number + * range starts with 1 + */ + public static final String FORK_NUMBER_PLACEHOLDER = "${surefire.forkNumber}"; + protected abstract String getPluginName(); private SurefireDependencyResolver dependencyResolver; @@ -664,6 +690,7 @@ public abstract class AbstractSurefireMojo } else { + convertDeprecatedForkMode(); ensureWorkingDirectoryExists(); ensureParallelRunningCompatibility(); ensureThreadCountWithPerThread(); @@ -772,9 +799,9 @@ public abstract class AbstractSurefireMojo new RunOrderParameters( getRunOrder(), getStatisticsFileName( getConfigChecksum() ) ); final RunResult result; - if ( isForkModeNever() ) + if ( isNotForking() ) { - createCopyAndReplaceThreadNumPlaceholder( effectiveProperties, 1 ).copyToSystemProperties(); + createCopyAndReplaceForkNumPlaceholder( effectiveProperties, 1 ).copyToSystemProperties(); InPluginVMSurefireStarter surefireStarter = createInprocessStarter( provider, classLoaderConfiguration, runOrderParameters ); @@ -793,7 +820,7 @@ public abstract class AbstractSurefireMojo { ForkStarter forkStarter = createForkStarter( provider, forkConfiguration, classLoaderConfiguration, runOrderParameters ); - result = forkStarter.run( effectiveProperties, scanResult, getEffectiveForkMode() ); + result = forkStarter.run( effectiveProperties, scanResult ); } finally { @@ -805,7 +832,7 @@ public abstract class AbstractSurefireMojo } - public static SurefireProperties createCopyAndReplaceThreadNumPlaceholder( + public static SurefireProperties createCopyAndReplaceForkNumPlaceholder( SurefireProperties effectiveSystemProperties, int threadNumber ) { SurefireProperties filteredProperties = new SurefireProperties( effectiveSystemProperties ); @@ -814,9 +841,11 @@ public abstract class AbstractSurefireMojo { if ( entry.getValue() instanceof String ) { - filteredProperties.put( entry.getKey(), - ( (String) entry.getValue() ).replace( THREAD_NUMBER_PLACEHOLDER, - threadNumberString ) ); + String value = (String) entry.getValue(); + value = value.replace( THREAD_NUMBER_PLACEHOLDER, threadNumberString ); + value = value.replace( FORK_NUMBER_PLACEHOLDER, threadNumberString ); + + filteredProperties.put( entry.getKey(), value ); } } return filteredProperties; @@ -941,11 +970,6 @@ public abstract class AbstractSurefireMojo return dependencyResolver.isWithinVersionSpec( artifact, "[4.0,)" ); } - boolean isForkModeNever() - { - return isForkModeNever( getEffectiveForkMode() ); - } - static boolean isForkModeNever( String forkMode ) { return ForkConfiguration.FORK_NEVER.equals( forkMode ); @@ -953,7 +977,7 @@ public abstract class AbstractSurefireMojo boolean isForking() { - return !isForkModeNever(); + return 0 < getEffectiveForkCount(); } String getEffectiveForkMode() @@ -1392,10 +1416,61 @@ public abstract class AbstractSurefireMojo getEffectiveForkCount(), reuseForks ); } + private void convertDeprecatedForkMode() + { + String effectiveForkMode = getEffectiveForkMode(); + // FORK_ONCE (default) is represented by the default values of forkCount and reuseForks + if ( ForkConfiguration.FORK_PERTHREAD.equals( effectiveForkMode ) ) + { + forkCount = String.valueOf(threadCount); + } + else if ( ForkConfiguration.FORK_NEVER.equals( effectiveForkMode ) ) + { + forkCount = "0"; + } else if ( ForkConfiguration.FORK_ALWAYS.equals( effectiveForkMode )) { + forkCount = "1"; + reuseForks = false; + } + + if ( !ForkConfiguration.FORK_ONCE.equals( getForkMode() ) ) + { + getLog().warn( "The parameter forkMode is deprecated since version 2.14. Use forkCount and reuseForks instead." ); + } + } - private int getEffectiveForkCount() + protected int getEffectiveForkCount() { - return ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) ? getThreadCount() : 1; + if ( effectiveForkCount < 0 ) + { + try + { + effectiveForkCount = convertWithCoreCount( forkCount ); + } + catch ( NumberFormatException ignored ) + { + } + + if ( effectiveForkCount < 0 ) + { + throw new IllegalArgumentException( "Fork count " + forkCount.trim() + " is not a legal value." ); + } + } + + return effectiveForkCount; + } + + protected int convertWithCoreCount( String count ) + { + String trimmed = count.trim(); + if ( trimmed.endsWith( "C" ) ) + { + double multiplier = Double.parseDouble( trimmed.substring( 0, trimmed.length() - 1 ) ); + return (int) ( multiplier * ( (double) Runtime.getRuntime().availableProcessors() ) ); + } + else + { + return Integer.parseInt( trimmed ); + } } private String getEffectiveDebugForkedProcess() @@ -1482,6 +1557,8 @@ public abstract class AbstractSurefireMojo checksum.add( isUseFile() ); checksum.add( isRedirectTestOutputToFile() ); checksum.add( getForkMode() ); + checksum.add( getForkCount() ); + checksum.add( isReuseForks() ); checksum.add( getJvm() ); checksum.add( getArgLine() ); checksum.add( getDebugForkedProcess() ); @@ -1770,9 +1847,9 @@ public abstract class AbstractSurefireMojo void ensureParallelRunningCompatibility() throws MojoFailureException { - if ( isMavenParallel() && isForkModeNever() ) + if ( isMavenParallel() && isNotForking() ) { - throw new MojoFailureException( "parallel maven execution is not compatible with surefire forkmode NEVER" ); + throw new MojoFailureException( "parallel maven execution is not compatible with surefire forkCount 0" ); } } @@ -1787,12 +1864,17 @@ public abstract class AbstractSurefireMojo void warnIfUselessUseSystemClassLoaderParameter() { - if ( isUseSystemClassLoader() && isForkModeNever() ) + if ( isUseSystemClassLoader() && isNotForking() ) { getLog().warn( "useSystemClassloader setting has no effect when not forking" ); } } + private boolean isNotForking() + { + return !isForking(); + } + void warnIfDefunctGroupsCombinations() throws MojoFailureException, MojoExecutionException { @@ -2478,4 +2560,13 @@ public abstract class AbstractSurefireMojo this.testSourceDirectory = testSourceDirectory; } + public String getForkCount() + { + return forkCount; + } + + public boolean isReuseForks() + { + return reuseForks; + } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java index 9f8780b..15d76a3 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java @@ -116,7 +116,6 @@ public class ForkConfiguration } } - /** * @param classPath cla the classpath arguments * @param classpathConfiguration the classpath configuration @@ -196,7 +195,8 @@ public class ForkConfiguration private String replaceThreadNumberPlaceholder( String argLine, int threadNumber ) { - return argLine.replace( AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER, String.valueOf( threadNumber ) ); + return argLine.replace( AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER, String.valueOf( threadNumber ) ) + .replace( AbstractSurefireMojo.FORK_NUMBER_PLACEHOLDER, String.valueOf( threadNumber ) ); } /** http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/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 6a2adea..85535e9 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 @@ -22,7 +22,6 @@ package org.apache.maven.plugin.surefire.booterclient; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.security.AccessControlException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -150,8 +149,7 @@ public class ForkStarter defaultReporterFactory = new DefaultReporterFactory( startupReportConfiguration ); } - public RunResult run( SurefireProperties effectiveSystemProperties, DefaultScanResult scanResult, - String requestedForkMode ) + public RunResult run( SurefireProperties effectiveSystemProperties, DefaultScanResult scanResult ) throws SurefireBooterForkException, SurefireExecutionException { final RunResult result; @@ -159,7 +157,7 @@ public class ForkStarter { Properties providerProperties = providerConfiguration.getProviderProperties(); scanResult.writeTo( providerProperties ); - if ( ForkConfiguration.FORK_ONCE.equals( requestedForkMode ) ) + if ( isForkOnce() ) { final ForkClient forkClient = new ForkClient( defaultReporterFactory, startupReportConfiguration.getTestVmSystemProperties() ); @@ -167,11 +165,11 @@ public class ForkStarter fork( null, new PropertiesWrapper( providerProperties ), forkClient, effectiveSystemProperties, 1, null ); } - else if ( ForkConfiguration.FORK_ALWAYS.equals( requestedForkMode ) ) + else if ( isForkAlways() ) { result = runSuitesForkPerTestSet( effectiveSystemProperties, 1 ); } - else if ( ForkConfiguration.FORK_PERTHREAD.equals( requestedForkMode ) ) + else { if ( forkConfiguration.isReuseForks() ) { @@ -182,10 +180,6 @@ public class ForkStarter result = runSuitesForkPerTestSet( effectiveSystemProperties, forkConfiguration.getForkCount() ); } } - else - { - throw new SurefireExecutionException( "Unknown forkmode: " + requestedForkMode, null ); - } } finally { @@ -194,6 +188,16 @@ public class ForkStarter return result; } + private boolean isForkAlways() + { + return !forkConfiguration.isReuseForks() && 1 == forkConfiguration.getForkCount(); + } + + private boolean isForkOnce() + { + return forkConfiguration.isReuseForks() && 1 == forkConfiguration.getForkCount(); + } + private RunResult runSuitesForkOncePerThread( final SurefireProperties effectiveSystemProperties, int forkCount ) throws SurefireBooterForkException { @@ -383,7 +387,7 @@ public class ForkStarter if ( effectiveSystemProperties != null ) { SurefireProperties filteredProperties = - AbstractSurefireMojo.createCopyAndReplaceThreadNumPlaceholder( effectiveSystemProperties, + AbstractSurefireMojo.createCopyAndReplaceForkNumPlaceholder( effectiveSystemProperties, threadNumber ); systPropsFile = SystemPropertyManager.writePropertiesFile( filteredProperties, http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java ---------------------------------------------------------------------- diff --git a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java index 5252a24..11abd51 100644 --- a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java +++ b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java @@ -1,79 +1,113 @@ -package org.apache.maven.plugin.surefire; -/* - * 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.lang.reflect.Field; -import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration; -import org.apache.maven.toolchain.Toolchain; - -import junit.framework.TestCase; - -public class SurefirePluginTest - extends TestCase -{ - - public void testForkMode() - throws NoSuchFieldException, IllegalAccessException - { - SurefirePlugin surefirePlugin = new SurefirePlugin(); - setFieldValue( surefirePlugin, "toolchain", new MyToolChain() ); - setFieldValue( surefirePlugin, "forkMode", "never" ); - assertEquals( ForkConfiguration.FORK_ONCE, surefirePlugin.getEffectiveForkMode() ); - } - - private void setFieldValue( SurefirePlugin plugin, String fieldName, Object value ) - throws NoSuchFieldException, IllegalAccessException - { - Field field = findField( plugin.getClass(), fieldName ); - field.setAccessible( true ); - field.set( plugin, value ); - - } - - private Field findField( Class clazz, String fieldName ) - { - while ( clazz != null ) - { - try - { - return clazz.getDeclaredField( fieldName ); - } - catch ( NoSuchFieldException e ) - { - clazz = clazz.getSuperclass(); - } - } - throw new IllegalArgumentException( "Field not found" ); - } - - private class MyToolChain - implements Toolchain - { - public String getType() - { - return null; - } - - public String findTool( String s ) - { - return null; - } - } -} +package org.apache.maven.plugin.surefire; +/* + * 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.lang.reflect.Field; +import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration; +import org.apache.maven.toolchain.Toolchain; + +import junit.framework.TestCase; + +public class SurefirePluginTest + extends TestCase +{ + + public void testForkMode() + throws NoSuchFieldException, IllegalAccessException + { + SurefirePlugin surefirePlugin = new SurefirePlugin(); + setFieldValue( surefirePlugin, "toolchain", new MyToolChain() ); + setFieldValue( surefirePlugin, "forkMode", "never" ); + assertEquals( ForkConfiguration.FORK_ONCE, surefirePlugin.getEffectiveForkMode() ); + } + + public void testForkCountComputation() + { + SurefirePlugin surefirePlugin = new SurefirePlugin(); + assertConversionFails( surefirePlugin, "nothing" ); + + assertConversionFails( surefirePlugin, "5,0" ); + assertConversionFails( surefirePlugin, "5.0" ); + assertConversionFails( surefirePlugin, "5,0C" ); + assertConversionFails( surefirePlugin, "5.0CC" ); + + assertForkCount( surefirePlugin, 5, "5" ); + + int availableProcessors = Runtime.getRuntime().availableProcessors(); + assertForkCount( surefirePlugin, 3*availableProcessors, "3C" ); + assertForkCount( surefirePlugin, (int) 2.5*availableProcessors, "2.5C" ); + assertForkCount( surefirePlugin, availableProcessors, "1.0001 C" ); + } + + private void assertForkCount( SurefirePlugin surefirePlugin, int expected, String value ) + { + assertEquals( expected, surefirePlugin.convertWithCoreCount( value )); + } + + private void assertConversionFails( SurefirePlugin surefirePlugin, String value ) + { + try { + surefirePlugin.convertWithCoreCount( value ); + } catch (NumberFormatException nfe) + { + return; + } + fail( "Expected NumberFormatException when converting " + value ); + } + + private void setFieldValue( SurefirePlugin plugin, String fieldName, Object value ) + throws NoSuchFieldException, IllegalAccessException + { + Field field = findField( plugin.getClass(), fieldName ); + field.setAccessible( true ); + field.set( plugin, value ); + + } + + private Field findField( Class clazz, String fieldName ) + { + while ( clazz != null ) + { + try + { + return clazz.getDeclaredField( fieldName ); + } + catch ( NoSuchFieldException e ) + { + clazz = clazz.getSuperclass(); + } + } + throw new IllegalArgumentException( "Field not found" ); + } + + private class MyToolChain + implements Toolchain + { + public String getType() + { + return null; + } + + public String findTool( String s ) + { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/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 fde17ea..35c53d7 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 @@ -19,6 +19,7 @@ package org.apache.maven.surefire.its; * under the License. */ +import java.lang.management.ManagementFactory; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -29,7 +30,7 @@ import org.apache.maven.surefire.its.fixture.TestFile; /** * Test forkMode - * + * * @author <a href="mailto:dfabul...@apache.org">Dan Fabulich</a> */ public class ForkModeIT @@ -39,36 +40,103 @@ public class ForkModeIT { String[] pids = doTest( unpack( getProject() ).debugLogging().forkAlways() ); assertDifferentPids( pids ); + assertEndWith( pids, "_1_1", 3); + assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) ); } public void testForkModePerTest() { String[] pids = doTest( unpack( getProject() ).debugLogging().forkPerTest() ); assertDifferentPids( pids ); + assertEndWith( pids, "_1_1", 3); + assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) ); } public void testForkModeNever() { String[] pids = doTest( unpack( getProject() ).debugLogging().forkNever() ); assertSamePids( pids ); + assertEndWith( pids, "_1_1", 3); + assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] ); } public void testForkModeNone() { String[] pids = doTest( unpack( getProject() ).debugLogging().forkMode( "none" ) ); assertSamePids( pids ); + assertEndWith( pids, "_1_1", 3); + assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] ); } public void testForkModeOncePerThreadSingleThread() { String[] pids = doTest( unpack( getProject() ).debugLogging().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() ) ); } public void testForkModeOncePerThreadTwoThreads() { - String[] pids = doTest( unpack( getProject() ).debugLogging().forkOncePerThread().threadCount( 2 ) ); + String[] pids = doTest( unpack( getProject() ).debugLogging().forkOncePerThread().threadCount( 2 ).addGoal( "-DsleepLength=1200" ) ); + assertDifferentPids( pids, 2 ); + assertEndWith( pids, "_1_1", 1); + assertEndWith( pids, "_2_2", 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 ) ); + assertSamePids( pids ); + assertEndWith( pids, "_1_1", 3); + assertEquals( "my pid is equal to pid 1 of the test", getMyPID(), pids[0] ); + } + + public void testForkCountOneNoReuse() + { + String[] pids = doTest( unpack( getProject() ).debugLogging().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() ) ); + } + + public void testForkCountOneReuse() + { + String[] pids = doTest( unpack( getProject() ).debugLogging().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() ) ); + } + + public void testForkCountTwoNoReuse() + { + String[] pids = doTest( unpack( getProject() ).debugLogging().forkCount( 2 ).reuseForks( false ).addGoal( "-DsleepLength=1200" ) ); + assertDifferentPids( pids ); + assertEndWith( pids, "_1_1", 1); + assertEndWith( pids, "_2_2", 2); + 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" ) ); assertDifferentPids( pids, 2 ); + assertEndWith( pids, "_1_1", 1); + assertEndWith( pids, "_2_2", 2); + assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) ); + } + + private void assertEndWith( String[] pids, String suffix, int expectedMatches ) + { + int matches = 0; + for (String pid : pids) { + if ( pid.endsWith( suffix )) { + matches++; + } + } + + assertEquals( "suffix " + suffix + " matched the correct number of pids", expectedMatches, matches ); } private void assertDifferentPids( String[] pids, int numOfDifferentPids ) @@ -80,11 +148,13 @@ public class ForkModeIT public void testForkModeOnce() { String[] pids = doTest( unpack( getProject() ).forkOnce() ); - // DGF It would be nice to assert that "once" was different - // from "never" ... but there's no way to check the PID of - // Maven itself. No matter, "once" is tested by setting - // argLine, which can't be done except by forking. assertSamePids( pids ); + assertFalse( "pid 1 is not the same as the main process' pid", pids[0].equals( getMyPID() ) ); + } + + private String getMyPID() + { + return ManagementFactory.getRuntimeMXBean().getName() + " testValue_1_1"; } private void assertSamePids( String[] pids ) @@ -113,7 +183,7 @@ public class ForkModeIT private String[] doTest( SurefireLauncher forkMode ) { - forkMode.sysProp( "testProperty", "testValue_${surefire.threadNumber}" ); + forkMode.sysProp( "testProperty", "testValue_${surefire.threadNumber}_${surefire.forkNumber}" ); final OutputValidator outputValidator = forkMode.executeTest(); outputValidator.verifyErrorFreeLog().assertTestSuiteResults( 3, 0, 0, 0 ); String[] pids = new String[3]; http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/01f5ddbc/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 135216e..201738f 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 @@ -233,14 +233,12 @@ public class SurefireLauncher public SurefireLauncher forkPerThread() { - return forkMode( "perthread" ); + return forkMode( "perthread" ).reuseForks( false ); } public SurefireLauncher forkOncePerThread() { - forkPerThread(); - mavenLauncher.sysProp( "reuseForks", true ); - return this; + return forkPerThread().reuseForks( true ); } public SurefireLauncher threadCount( int threadCount ) @@ -249,6 +247,18 @@ public class SurefireLauncher return this; } + public SurefireLauncher forkCount( int forkCount ) + { + mavenLauncher.sysProp( "forkCount", forkCount ); + return this; + } + + public SurefireLauncher reuseForks( boolean reuseForks ) + { + mavenLauncher.sysProp( "reuseForks", reuseForks ); + return this; + } + public SurefireLauncher forkMode( String forkMode ) { mavenLauncher.sysProp( "forkMode", forkMode );