Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[SUREFIRE-751] forkMode=onceperthread

  • Loading branch information...
commit 9c6ce9be423219e88d6e9c777ba69eea5e831d0c 1 parent 0b27dc2
@agudian agudian authored krosenvold committed
Showing with 722 additions and 139 deletions.
  1. +35 −10 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
  2. +6 −2 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
  3. +18 −7 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
  4. +145 −27 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
  5. +7 −0 ...fire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/FlushReceiver.java
  6. +5 −0 ...mon/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/FlushReceiverProvider.java
  7. +41 −0 ...n/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/ProcessAwareCommandline.java
  8. +52 −0 .../src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
  9. +17 −0 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
  10. +44 −15 ...rc/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
  11. +5 −5 ...src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
  12. +2 −2 maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
  13. +1 −1  pom.xml
  14. +3 −0  surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
  15. +135 −0 surefire-api/src/main/java/org/apache/maven/surefire/util/LazyTestsToRun.java
  16. +1 −0  surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
  17. +4 −1 surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
  18. +14 −1 surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
  19. +10 −2 surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
  20. +23 −1 surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
  21. +10 −0 surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
  22. +1 −2  ...ation-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire907PerThreadWithoutThreadCountIT.java
  23. +1 −0  surefire-integration-tests/src/test/resources/fork-mode-testng/pom.xml
  24. +5 −0 surefire-integration-tests/src/test/resources/fork-mode-testng/src/test/java/forkMode/Test1.java
  25. +1 −0  surefire-integration-tests/src/test/resources/fork-mode/pom.xml
  26. +6 −1 surefire-integration-tests/src/test/resources/fork-mode/src/test/java/forkMode/Test1.java
  27. +11 −1 surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
  28. +14 −4 surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
  29. +11 −6 surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
  30. +14 −9 surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java
  31. +69 −41 ...fire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java
  32. +11 −1 surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
View
45 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -29,6 +29,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
@@ -327,8 +328,11 @@
protected Boolean failIfNoTests;
/**
- * Option to specify the forking mode. Can be "never", "once", "always" or "perthread". "none" and "pertest" are also accepted
- * for backwards compatibility. "always" forks for each test-class. "perthread" will create "threadCount" parallel forks.
+ * Option to specify the forking mode. Can be "never", "once", "always", "perthread" or "onceperthread". "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.
+ * "onceperthread" will fork "threadCount" processes that each execute a 1/"threadCount" of all test-classes.<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".
*
* @since 2.1
*/
@@ -429,9 +433,9 @@
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. (forkMode=perthread
- * does not support/require the <code>parallel</code> parameter)
+ * (forkMode=perthread, forkmode=onceperthread 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
+ * or forkmode=onceperthread.
*
* @since 2.2
*/
@@ -572,6 +576,12 @@
private Artifact surefireBooterArtifact;
private Toolchain toolchain;
+
+ /**
+ * The placeholder that is replaced by the executing thread's running number. The thread number
+ * range starts with 1
+ */
+ public static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}";
protected abstract String getPluginName();
@@ -741,7 +751,8 @@ private RunResult executeProvider( ProviderInfo provider, DefaultScanResult scan
final RunResult result;
if ( isForkModeNever() )
{
- effectiveProperties.copyToSystemProperties();
+ createCopyAndReplaceThreadNumPlaceholder(effectiveProperties, 1).copyToSystemProperties();
+
InPluginVMSurefireStarter surefireStarter =
createInprocessStarter( provider, classLoaderConfiguration, runOrderParameters );
result = surefireStarter.runSuitesInProcess( scanResult );
@@ -771,6 +782,18 @@ private RunResult executeProvider( ProviderInfo provider, DefaultScanResult scan
return result;
}
+
+ public static SurefireProperties createCopyAndReplaceThreadNumPlaceholder(SurefireProperties effectiveSystemProperties, int threadNumber) {
+ SurefireProperties filteredProperties = new SurefireProperties(effectiveSystemProperties);
+ String threadNumberString = String.valueOf(threadNumber);
+ for (Entry<Object,Object> entry : effectiveSystemProperties.entrySet()) {
+ if (entry.getValue() instanceof String) {
+ filteredProperties.put(entry.getKey(), ((String)entry.getValue()).replace(THREAD_NUMBER_PLACEHOLDER, threadNumberString));
+ }
+ }
+ return filteredProperties;
+ }
+
protected void cleanupForkConfiguration( ForkConfiguration forkConfiguration )
{
if ( !getLog().isDebugEnabled() && forkConfiguration != null )
@@ -1002,7 +1025,7 @@ private ProviderConfiguration createProviderConfiguration( RunOrderParameters ru
return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, failIfNoTests,
reporterConfiguration, testNg, testSuiteDefinition, providerProperties,
- null );
+ null, false );
}
public String getStatisticsFileName( String configurationHash )
@@ -1344,7 +1367,8 @@ protected ForkConfiguration getForkConfiguration()
private int getEffectiveForkCount()
{
- return ( ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) ) ? getThreadCount() : 1;
+ return ( ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) ||
+ ForkConfiguration.FORK_ONCE_PERTHREAD.equals( getEffectiveForkMode() ) ) ? getThreadCount() : 1;
}
private String getEffectiveDebugForkedProcess()
@@ -1728,9 +1752,10 @@ void ensureParallelRunningCompatibility()
void ensureThreadCountWithPerThread()
throws MojoFailureException
{
- if ( ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) && getThreadCount() < 1 )
+ if ( ( ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) ||
+ ForkConfiguration.FORK_ONCE_PERTHREAD.equals( getEffectiveForkMode() )) && getThreadCount() < 1 )
{
- throw new MojoFailureException( "Fork mode perthread requires a thread count" );
+ throw new MojoFailureException( "Fork modes perthread and onceperthread require a thread count" );
}
}
View
8 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
@@ -21,7 +21,9 @@
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.Properties;
+
import org.apache.maven.surefire.booter.BooterConstants;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.KeyValueSource;
@@ -66,7 +68,7 @@ public BooterSerializer( ForkConfiguration forkConfiguration )
DOes not modify sourceProperties
*/
public File serialize(KeyValueSource sourceProperties, ProviderConfiguration booterConfiguration, StartupConfiguration providerConfiguration,
- Object testSet)
+ Object testSet, boolean readTestsFromInStream)
throws IOException
{
@@ -82,7 +84,9 @@ public File serialize(KeyValueSource sourceProperties, ProviderConfiguration boo
properties.setProperty( BooterConstants.TESTARTIFACT_CLASSIFIER, testNg.getClassifier() );
}
- properties.setProperty( BooterConstants.FORKTESTSET, getTypeEncoded( testSet ) );
+ properties.setProperty( BooterConstants.FORKTESTSET_PREFER_TESTS_FROM_IN_STREAM, Boolean.valueOf( readTestsFromInStream ) );
+ properties.setProperty( BooterConstants.FORKTESTSET, getTypeEncoded( testSet ) );
+
TestRequest testSuiteDefinition = booterConfiguration.getTestSuiteDefinition();
if ( testSuiteDefinition != null )
{
View
25 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
@@ -27,6 +27,9 @@
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
+
+import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.ProcessAwareCommandline;
import org.apache.maven.plugin.surefire.util.Relocator;
import org.apache.maven.shared.utils.StringUtils;
import org.apache.maven.shared.utils.cli.Commandline;
@@ -52,6 +55,8 @@
public static final String FORK_NEVER = "never";
public static final String FORK_PERTHREAD = "perthread";
+
+ public static final String FORK_ONCE_PERTHREAD = "onceperthread";
private final int forkCount;
@@ -102,7 +107,8 @@ else if ( "none".equalsIgnoreCase( forkMode ) )
return FORK_NEVER;
}
else if ( forkMode.equals( FORK_NEVER ) || forkMode.equals( FORK_ONCE ) ||
- forkMode.equals( FORK_ALWAYS ) || forkMode.equals( FORK_PERTHREAD ) )
+ forkMode.equals( FORK_ALWAYS ) || forkMode.equals( FORK_PERTHREAD ) ||
+ forkMode.equals( FORK_ONCE_PERTHREAD ))
{
return forkMode;
}
@@ -117,27 +123,28 @@ else if ( forkMode.equals( FORK_NEVER ) || forkMode.equals( FORK_ONCE ) ||
* @param classPath cla the classpath arguments
* @param classpathConfiguration the classpath configuration
* @param shadefire true if running shadefire
+ * @param threadNumber the thread number, to be the replacement in the argLine
* @return A commandline
* @throws org.apache.maven.surefire.booter.SurefireBooterForkException
* when unable to perform the fork
*/
- public Commandline createCommandLine( List<String> classPath, ClassLoaderConfiguration classpathConfiguration,
- boolean shadefire )
+ public ProcessAwareCommandline createCommandLine( List<String> classPath, ClassLoaderConfiguration classpathConfiguration,
+ boolean shadefire, int threadNumber )
throws SurefireBooterForkException
{
- return createCommandLine( classPath, classpathConfiguration.isManifestOnlyJarRequestedAndUsable(), shadefire );
+ return createCommandLine( classPath, classpathConfiguration.isManifestOnlyJarRequestedAndUsable(), shadefire, threadNumber );
}
- public Commandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire )
+ public ProcessAwareCommandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire, int threadNumber )
throws SurefireBooterForkException
{
- Commandline cli = new Commandline();
+ ProcessAwareCommandline cli = new ProcessAwareCommandline();
cli.setExecutable( jvmExecutable );
if ( argLine != null )
{
- cli.createArg().setLine( stripNewLines( argLine ) );
+ cli.createArg().setLine( replaceThreadNumberPlaceholder(stripNewLines( argLine ), threadNumber) );
}
if ( environmentVariables != null )
@@ -186,6 +193,10 @@ public Commandline createCommandLine( List<String> classPath, boolean useJar, bo
return cli;
}
+ private String replaceThreadNumberPlaceholder(String argLine, int threadNumber) {
+ return argLine.replace(AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER, String.valueOf(threadNumber));
+ }
+
/**
* Create a jar with just a manifest containing a Main-Class entry for BooterConfiguration and a Class-Path entry
* for all classpath elements.
View
172 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -23,24 +23,31 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
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;
import org.apache.maven.plugin.surefire.StartupReportConfiguration;
import org.apache.maven.plugin.surefire.SurefireProperties;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.ProcessAwareCommandline;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.shared.utils.cli.CommandLineException;
import org.apache.maven.shared.utils.cli.CommandLineTimeOutException;
import org.apache.maven.shared.utils.cli.CommandLineUtils;
-import org.apache.maven.shared.utils.cli.Commandline;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
import org.apache.maven.surefire.booter.KeyValueSource;
@@ -52,9 +59,9 @@
import org.apache.maven.surefire.booter.SurefireExecutionException;
import org.apache.maven.surefire.booter.SystemPropertyManager;
import org.apache.maven.surefire.providerapi.SurefireProvider;
-import org.apache.maven.surefire.report.RunStatistics;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.util.DefaultScanResult;
+import org.codehaus.plexus.util.CollectionUtils;
/**
@@ -87,6 +94,17 @@
private static volatile int systemPropertiesFileCounter = 0;
+ private final ThreadLocal<Integer> threadNumber = new ThreadLocal<Integer>()
+ {
+ private final AtomicInteger nextThreadNumber = new AtomicInteger( 1 );
+
+ @Override
+ protected Integer initialValue()
+ {
+ return nextThreadNumber.getAndIncrement();
+ }
+ };
+
public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
ForkConfiguration forkConfiguration, int forkedProcessTimeoutInSeconds,
@@ -113,17 +131,21 @@ public RunResult run( SurefireProperties effectiveSystemProperties, DefaultScanR
{
final ForkClient forkClient =
new ForkClient( fileReporterFactory, startupReportConfiguration.getTestVmSystemProperties() );
- result = fork( null, new PropertiesWrapper( providerProperties ), forkClient,
- fileReporterFactory.getGlobalRunStatistics(), effectiveSystemProperties );
+ result =
+ fork( null, new PropertiesWrapper( providerProperties ), forkClient, effectiveSystemProperties, 1,
+ null );
}
else if ( ForkConfiguration.FORK_ALWAYS.equals( requestedForkMode ) )
{
- result = runSuitesForkPerTestSet( providerProperties, effectiveSystemProperties, 1 );
+ result = runSuitesForkPerTestSet( effectiveSystemProperties, 1 );
}
else if ( ForkConfiguration.FORK_PERTHREAD.equals( requestedForkMode ) )
{
- result = runSuitesForkPerTestSet( providerProperties, effectiveSystemProperties,
- forkConfiguration.getForkCount() );
+ result = runSuitesForkPerTestSet( effectiveSystemProperties, forkConfiguration.getForkCount() );
+ }
+ else if ( ForkConfiguration.FORK_ONCE_PERTHREAD.equals( requestedForkMode ) )
+ {
+ result = runSuitesForkOncePerThread( effectiveSystemProperties, forkConfiguration.getForkCount() );
}
else
{
@@ -137,8 +159,85 @@ else if ( ForkConfiguration.FORK_PERTHREAD.equals( requestedForkMode ) )
return result;
}
- private RunResult runSuitesForkPerTestSet( final Properties properties,
- final SurefireProperties effectiveSystemProperties, int forkCount )
+ private RunResult runSuitesForkOncePerThread( final SurefireProperties effectiveSystemProperties, int forkCount )
+ throws SurefireBooterForkException
+ {
+
+ ArrayList<Future<RunResult>> results = new ArrayList<Future<RunResult>>( forkCount );
+ ExecutorService executorService = new ThreadPoolExecutor( forkCount, forkCount, 60, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>( forkCount ) );
+
+ try
+ {
+ // Ask to the executorService to run all tasks
+ RunResult globalResult = new RunResult( 0, 0, 0, 0 );
+
+ List<Class<?>> suites = CollectionUtils.iteratorToList( getSuitesIterator() );
+ final Queue<String> messageQueue = new ConcurrentLinkedQueue<String>();
+ for ( Class<?> clazz : suites )
+ {
+ messageQueue.add( clazz.getName() );
+ }
+
+ for ( int threadNum = 0; threadNum < forkCount && threadNum < suites.size(); threadNum++ )
+ {
+ final int finalThreadNumber = threadNum + 1;
+
+ Callable<RunResult> pf = new Callable<RunResult>()
+ {
+ public RunResult call()
+ throws Exception
+ {
+ TestProvidingInputStream testProvidingInputStream =
+ new TestProvidingInputStream( messageQueue );
+
+ ForkClient forkClient =
+ new ForkClient( fileReporterFactory, startupReportConfiguration.getTestVmSystemProperties(),
+ testProvidingInputStream );
+
+ return fork( null, new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
+ forkClient, effectiveSystemProperties, finalThreadNumber,
+ testProvidingInputStream );
+ }
+ };
+
+ results.add( executorService.submit( pf ) );
+ }
+
+ for ( Future<RunResult> result : results )
+ {
+ try
+ {
+ RunResult cur = result.get();
+ if ( cur != null )
+ {
+ globalResult = globalResult.aggregate( cur );
+ }
+ else
+ {
+ throw new SurefireBooterForkException( "No results for " + result.toString() );
+ }
+ }
+ catch ( InterruptedException e )
+ {
+ throw new SurefireBooterForkException( "Interrupted", e );
+ }
+ catch ( ExecutionException e )
+ {
+ throw new SurefireBooterForkException( "ExecutionException", e );
+ }
+ }
+ return globalResult;
+
+ }
+ finally
+ {
+ closeExecutor( executorService );
+ }
+
+ }
+
+ private RunResult runSuitesForkPerTestSet( final SurefireProperties effectiveSystemProperties, final int forkCount )
throws SurefireBooterForkException
{
@@ -150,19 +249,27 @@ private RunResult runSuitesForkPerTestSet( final Properties properties,
{
// Ask to the executorService to run all tasks
RunResult globalResult = new RunResult( 0, 0, 0, 0 );
- final Iterator suites = getSuitesIterator();
+ final Iterator<Class<?>> suites = getSuitesIterator();
while ( suites.hasNext() )
{
final Object testSet = suites.next();
- final ForkClient forkClient =
- new ForkClient( fileReporterFactory, startupReportConfiguration.getTestVmSystemProperties() );
Callable<RunResult> pf = new Callable<RunResult>()
{
public RunResult call()
throws Exception
{
- return fork( testSet, new PropertiesWrapper( properties ), forkClient,
- fileReporterFactory.getGlobalRunStatistics(), effectiveSystemProperties );
+ int thisThreadsThreadNumber = threadNumber.get();
+ if ( thisThreadsThreadNumber > 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( fileReporterFactory,
+ startupReportConfiguration.getTestVmSystemProperties() );
+ return fork( testSet, new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
+ forkClient, effectiveSystemProperties, thisThreadsThreadNumber, null );
}
};
results.add( executorService.submit( pf ) );
@@ -217,9 +324,9 @@ private void closeExecutor( ExecutorService executorService )
}
}
-
private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
- RunStatistics globalRunStatistics, SurefireProperties effectiveSystemProperties )
+ SurefireProperties effectiveSystemProperties, int threadNumber,
+ TestProvidingInputStream testProvidingInputStream )
throws SurefireBooterForkException
{
File surefireProperties;
@@ -229,14 +336,18 @@ private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkC
BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
surefireProperties =
- booterSerializer.serialize( providerProperties, providerConfiguration, startupConfiguration, testSet );
+ booterSerializer.serialize( providerProperties, providerConfiguration, startupConfiguration, testSet,
+ null != testProvidingInputStream );
if ( effectiveSystemProperties != null )
{
- systPropsFile = SystemPropertyManager.writePropertiesFile( effectiveSystemProperties,
- forkConfiguration.getTempDirectory(),
- "surefire_" + systemPropertiesFileCounter++,
- forkConfiguration.isDebug() );
+ SurefireProperties filteredProperties =
+ AbstractSurefireMojo.createCopyAndReplaceThreadNumPlaceholder( effectiveSystemProperties,
+ threadNumber );
+ systPropsFile =
+ SystemPropertyManager.writePropertiesFile( filteredProperties, forkConfiguration.getTempDirectory(),
+ "surefire_" + systemPropertiesFileCounter++,
+ forkConfiguration.isDebug() );
}
}
catch ( IOException e )
@@ -254,10 +365,15 @@ private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkC
// Surefire-booter if !useSystemClassLoader
Classpath bootClasspath = Classpath.join( bootClasspathConfiguration, additionlClassPathUrls );
- @SuppressWarnings( "unchecked" ) Commandline cli =
+ @SuppressWarnings( "unchecked" ) ProcessAwareCommandline cli =
forkConfiguration.createCommandLine( bootClasspath.getClassPath(),
startupConfiguration.getClassLoaderConfiguration(),
- startupConfiguration.isShadefire() );
+ startupConfiguration.isShadefire(), threadNumber );
+
+ if ( testProvidingInputStream != null )
+ {
+ testProvidingInputStream.setFlushReceiverProvider( cli );
+ }
cli.createArg().setFile( surefireProperties );
@@ -279,7 +395,8 @@ private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkC
{
final int timeout = forkedProcessTimeoutInSeconds > 0 ? forkedProcessTimeoutInSeconds : 0;
final int result =
- CommandLineUtils.executeCommandLine( cli, threadedStreamConsumer, threadedStreamConsumer, timeout );
+ CommandLineUtils.executeCommandLine( cli, testProvidingInputStream, threadedStreamConsumer,
+ threadedStreamConsumer, timeout );
if ( result != RunResult.SUCCESS )
{
throw new SurefireBooterForkException( "Error occurred in starting fork, check output in log" );
@@ -299,17 +416,18 @@ private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkC
finally
{
threadedStreamConsumer.close();
- forkClient.close(runResult == RunResult.Timeout);
+ forkClient.close( runResult == RunResult.Timeout );
if ( runResult == null )
{
- runResult = globalRunStatistics.getRunResult();
+ runResult = fileReporterFactory.getGlobalRunStatistics().getRunResult();
}
}
return runResult;
}
- private Iterator getSuitesIterator()
+ @SuppressWarnings( "unchecked" )
+ private Iterator<Class<?>> getSuitesIterator()
throws SurefireBooterForkException
{
try
View
7 ...e-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/FlushReceiver.java
@@ -0,0 +1,7 @@
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
+
+import java.io.IOException;
+
+public interface FlushReceiver {
+ void flush() throws IOException;
+}
View
5 .../src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/FlushReceiverProvider.java
@@ -0,0 +1,5 @@
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
+
+public interface FlushReceiverProvider {
+ FlushReceiver getFlushReceiver();
+}
View
41 ...rc/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/ProcessAwareCommandline.java
@@ -0,0 +1,41 @@
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.maven.shared.utils.cli.CommandLineException;
+import org.apache.maven.shared.utils.cli.Commandline;
+
+
+
+public class ProcessAwareCommandline extends Commandline implements FlushReceiverProvider {
+ private final class OutputStreamFlushReceiver implements FlushReceiver {
+ private final OutputStream outputStream;
+
+ private OutputStreamFlushReceiver(OutputStream outputStream) {
+ this.outputStream = outputStream;
+ }
+
+ public void flush() throws IOException {
+ outputStream.flush();
+ }
+ }
+
+ private FlushReceiver flushReceiver;
+
+ @Override
+ public Process execute() throws CommandLineException {
+ Process process = super.execute();
+
+ if (process.getOutputStream() != null) {
+ flushReceiver = new OutputStreamFlushReceiver(process.getOutputStream());
+ }
+
+ return process;
+ }
+
+ public FlushReceiver getFlushReceiver() {
+ return flushReceiver;
+ }
+
+}
View
52 ...c/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
@@ -0,0 +1,52 @@
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Queue;
+import java.util.concurrent.Semaphore;
+
+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;
+
+ public TestProvidingInputStream(Queue<String> testItemQueue) {
+ this.testItemQueue = testItemQueue;
+ }
+
+ 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();
+
+ 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);
+ }
+ }
+
+ public void provideNewTest() {
+ semaphore.release();
+ }
+}
View
17 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -28,6 +28,8 @@
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
+
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.shared.utils.cli.StreamConsumer;
import org.apache.maven.surefire.booter.ForkingRunListener;
@@ -36,6 +38,7 @@
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.ReporterException;
+import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.util.NestedRuntimeException;
@@ -49,7 +52,9 @@
public class ForkClient
implements StreamConsumer
{
+
private final DefaultReporterFactory providerReporterFactory;
+ private final TestProvidingInputStream testProvidingInputStream;
private final Map<Integer, RunListener> testSetReporters =
Collections.synchronizedMap( new HashMap<Integer, RunListener>() );
@@ -60,8 +65,14 @@
public ForkClient( DefaultReporterFactory providerReporterFactory, Properties testVmSystemProperties )
{
+ this(providerReporterFactory, testVmSystemProperties, null);
+ }
+
+ public ForkClient( DefaultReporterFactory providerReporterFactory, Properties testVmSystemProperties, TestProvidingInputStream testProvidingInputStream )
+ {
this.providerReporterFactory = providerReporterFactory;
this.testVmSystemProperties = testVmSystemProperties;
+ this.testProvidingInputStream = testProvidingInputStream;
}
public void consumeLine( String s )
@@ -134,6 +145,12 @@ public void consumeLine( String s )
case ForkingRunListener.BOOTERCODE_CONSOLE:
getOrCreateConsoleLogger( channelNumber ).info( createConsoleMessage( remaining ) );
break;
+ case ForkingRunListener.BOOTERCODE_NEXT_TEST:
+ if (null != testProvidingInputStream)
+ {
+ testProvidingInputStream.provideNewTest();
+ }
+ break;
case ForkingRunListener.BOOTERCODE_BYE:
saidGoodBye = true;
break;
View
59 ...test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
@@ -27,13 +27,16 @@
import java.util.Collections;
import java.util.List;
import java.util.Properties;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
import org.apache.maven.surefire.booter.BooterDeserializer;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
-import org.apache.maven.surefire.booter.SystemPropertyManager;
import org.apache.maven.surefire.booter.TypeEncodedValue;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
@@ -42,9 +45,6 @@
import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.RunOrder;
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
/**
* Performs roundtrip testing of serialization/deserialization of the ProviderConfiguration
*
@@ -55,7 +55,7 @@
{
public static final TypeEncodedValue aTestTyped = new TypeEncodedValue( String.class.getName(), "aTest" );
-
+
private final String aUserRequestedTest = "aUserRequestedTest";
private static ClassLoaderConfiguration getForkConfiguration()
@@ -79,7 +79,7 @@ public void testDirectoryScannerParams()
ClassLoaderConfiguration forkConfiguration = getForkConfiguration();
final StartupConfiguration testStartupConfiguration = getTestStartupConfiguration( forkConfiguration );
ProviderConfiguration providerConfiguration = getReloadedProviderConfiguration();
- ProviderConfiguration read = saveAndReload( providerConfiguration, testStartupConfiguration );
+ ProviderConfiguration read = saveAndReload( providerConfiguration, testStartupConfiguration, false );
Assert.assertEquals( aDir, read.getBaseDir() );
Assert.assertEquals( includes.get( 0 ), read.getIncludes().get( 0 ) );
@@ -95,10 +95,10 @@ public void testReporterConfiguration()
DirectoryScannerParameters directoryScannerParameters = getDirectoryScannerParametersWithoutSpecificTests();
ClassLoaderConfiguration forkConfiguration = getForkConfiguration();
- ProviderConfiguration providerConfiguration = getTestProviderConfiguration( directoryScannerParameters );
+ ProviderConfiguration providerConfiguration = getTestProviderConfiguration( directoryScannerParameters, false );
final StartupConfiguration testProviderConfiguration = getTestStartupConfiguration( forkConfiguration );
- ProviderConfiguration reloaded = saveAndReload( providerConfiguration, testProviderConfiguration );
+ ProviderConfiguration reloaded = saveAndReload( providerConfiguration, testProviderConfiguration, false );
assertTrue( reloaded.getReporterConfiguration().isTrimStackTrace().booleanValue() );
assertNotNull( reloaded.getReporterConfiguration().getReportsDirectory() );
@@ -134,6 +134,15 @@ public void testTestForFork()
Assert.assertEquals( aTestTyped, reloaded.getTestForFork() );
}
+
+ public void testTestForForkWithMultipleFiles()
+ throws IOException
+ {
+ final ProviderConfiguration reloaded = getReloadedProviderConfigurationForReadFromInStream();
+ Assert.assertNull( reloaded.getTestForFork() );
+ Assert.assertTrue( reloaded.isReadTestsFromInStream() );
+
+ }
public void testFailIfNoTests()
throws IOException
@@ -143,14 +152,26 @@ public void testFailIfNoTests()
}
+ private ProviderConfiguration getReloadedProviderConfigurationForReadFromInStream()
+ throws IOException
+ {
+ return getReloadedProviderConfiguration(true);
+ }
+
private ProviderConfiguration getReloadedProviderConfiguration()
+ throws IOException
+ {
+ return getReloadedProviderConfiguration(false);
+ }
+
+ private ProviderConfiguration getReloadedProviderConfiguration(boolean readTestsFromInStream)
throws IOException
{
DirectoryScannerParameters directoryScannerParameters = getDirectoryScannerParametersWithoutSpecificTests();
ClassLoaderConfiguration forkConfiguration = getForkConfiguration();
- ProviderConfiguration booterConfiguration = getTestProviderConfiguration( directoryScannerParameters );
+ ProviderConfiguration booterConfiguration = getTestProviderConfiguration( directoryScannerParameters, readTestsFromInStream );
final StartupConfiguration testProviderConfiguration = getTestStartupConfiguration( forkConfiguration );
- return saveAndReload( booterConfiguration, testProviderConfiguration );
+ return saveAndReload( booterConfiguration, testProviderConfiguration, readTestsFromInStream );
}
private DirectoryScannerParameters getDirectoryScannerParametersWithoutSpecificTests()
@@ -168,19 +189,27 @@ private DirectoryScannerParameters getDirectoryScannerParametersWithoutSpecificT
}
private ProviderConfiguration saveAndReload( ProviderConfiguration booterConfiguration,
- StartupConfiguration testProviderConfiguration )
+ StartupConfiguration testProviderConfiguration, boolean readTestsFromInStream )
throws IOException
{
final ForkConfiguration forkConfiguration = ForkConfigurationTest.getForkConfiguration( null, null );
PropertiesWrapper props = new PropertiesWrapper( new Properties());
BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
- String aTest = "aTest";
- final File propsTest = booterSerializer.serialize( props, booterConfiguration, testProviderConfiguration, aTest);
+ Object test;
+ if (readTestsFromInStream)
+ {
+ test = null;
+ }
+ else
+ {
+ test = "aTest";
+ }
+ final File propsTest = booterSerializer.serialize( props, booterConfiguration, testProviderConfiguration, test, readTestsFromInStream);
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
return booterDeserializer.deserialize();
}
- private ProviderConfiguration getTestProviderConfiguration( DirectoryScannerParameters directoryScannerParameters )
+ private ProviderConfiguration getTestProviderConfiguration( DirectoryScannerParameters directoryScannerParameters, boolean readTestsFromInStream )
{
File cwd = new File( "." );
@@ -192,7 +221,7 @@ private ProviderConfiguration getTestProviderConfiguration( DirectoryScannerPara
RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, null );
return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, true, reporterConfiguration,
new TestArtifactInfo( "5.0", "ABC" ), testSuiteDefinition, new Properties(),
- aTestTyped );
+ aTestTyped, readTestsFromInStream );
}
private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
View
10 .../test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -25,6 +25,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Properties;
+
+import junit.framework.TestCase;
+
import org.apache.maven.surefire.booter.BooterDeserializer;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.Classpath;
@@ -32,7 +35,6 @@
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
-import org.apache.maven.surefire.booter.SystemPropertyManager;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
import org.apache.maven.surefire.testset.RunOrderParameters;
@@ -40,8 +42,6 @@
import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.RunOrder;
-import junit.framework.TestCase;
-
/**
* Performs roundtrip testing of serialization/deserialization of The StartupConfiguration
*
@@ -130,7 +130,7 @@ private StartupConfiguration saveAndReload( StartupConfiguration startupConfigur
PropertiesWrapper props = new PropertiesWrapper( new Properties());
BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
String aTest = "aTest";
- final File propsTest = booterSerializer.serialize( props, getProviderConfiguration(), startupConfiguration, aTest);
+ final File propsTest = booterSerializer.serialize( props, getProviderConfiguration(), startupConfiguration, aTest, false );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
return booterDeserializer.getProviderConfiguration();
}
@@ -152,7 +152,7 @@ private ProviderConfiguration getProviderConfiguration()
RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, null );
return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, true, reporterConfiguration,
new TestArtifactInfo( "5.0", "ABC" ), testSuiteDefinition, new Properties(),
- BooterDeserializerProviderConfigurationTest.aTestTyped );
+ BooterDeserializerProviderConfigurationTest.aTestTyped, true );
}
private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
View
4 ...n-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -41,7 +41,7 @@ public void testCreateCommandLine_UseSystemClassLoaderForkOnce_ShouldConstructMa
File cpElement = getTempClasspathFile();
Commandline cli =
- config.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), true, false );
+ config.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), true, false, 1 );
String line = StringUtils.join( cli.getCommandline(), " " );
assertTrue( line.contains( "-jar" ) );
@@ -56,7 +56,7 @@ public void testArglineWithNewline()
final Commandline commandLine =
forkConfiguration.createCommandLine( Collections.singletonList( cpElement.getAbsolutePath() ), false,
- false );
+ false, 1 );
assertTrue( commandLine.toString().contains( "abc def" ) );
}
View
2  pom.xml
@@ -222,7 +222,7 @@
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-utils</artifactId>
- <version>0.1</version>
+ <version>0.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>jmock</groupId>
View
3  surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -22,6 +22,7 @@
import java.io.PrintStream;
import java.util.Enumeration;
import java.util.Properties;
+
import org.apache.maven.surefire.report.ConsoleLogger;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
@@ -75,6 +76,8 @@
public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';
+ public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';
+
public static final byte BOOTERCODE_BYE = (byte) 'Z';
private final PrintStream target;
View
135 surefire-api/src/main/java/org/apache/maven/surefire/util/LazyTestsToRun.java
@@ -0,0 +1,135 @@
+/**
+ *
+ */
+package org.apache.maven.surefire.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.surefire.booter.ForkingRunListener;
+
+/**
+ * A variant of TestsToRun that is provided with test class names asynchronously
+ * from an {@link InputStream} (e.g. {@code System.in}). The method
+ * {@link #iterator()} returns an Iterator that blocks on calls to
+ * {@link Iterator#hasNext()} until new classes are available, or no more
+ * classes will be available.
+ * <p/>
+ * The methods {@link #getLocatedClasses()} and {@link #size()} will throw an
+ * {@link UnsupportedOperationException}.
+ *
+ * @author Andreas Gudian
+ *
+ */
+public class LazyTestsToRun extends TestsToRun {
+ private List workQueue = new ArrayList();
+ private BufferedReader inputReader;
+ private boolean streamClosed = false;
+ private ClassLoader testClassLoader;
+ private PrintStream originalOutStream;
+
+ public LazyTestsToRun(InputStream testSource, ClassLoader testClassLoader, PrintStream originalOutStream) {
+ super(Collections.emptyList());
+
+ this.testClassLoader = testClassLoader;
+ this.originalOutStream = originalOutStream;
+
+ inputReader = new BufferedReader(new InputStreamReader(testSource));
+ }
+
+ protected void addWorkItem(String className) {
+ synchronized (workQueue) {
+ workQueue.add(ReflectionUtils.loadClass(testClassLoader, className));
+ }
+ }
+
+ protected void requestNextTest() {
+ StringBuffer sb = new StringBuffer();
+ sb.append((char) ForkingRunListener.BOOTERCODE_NEXT_TEST).append(",0,want more!\n");
+ originalOutStream.print(sb.toString());
+ }
+
+ private class BlockingIterator implements Iterator {
+ private int lastPos = -1;
+
+ public boolean hasNext() {
+ int nextPos = lastPos + 1;
+ synchronized (workQueue) {
+ if (workQueue.size() > nextPos) {
+ return true;
+ } else {
+ if (needsToWaitForInput(nextPos)) {
+ requestNextTest();
+
+ String nextClassName;
+ try {
+ nextClassName = inputReader.readLine();
+ } catch (IOException e) {
+ streamClosed = true;
+ return false;
+ }
+
+ if (null == nextClassName) {
+ streamClosed = true;
+ } else {
+ addWorkItem(nextClassName);
+ }
+ }
+
+ return (workQueue.size() > nextPos);
+ }
+ }
+ }
+
+ private boolean needsToWaitForInput(int nextPos) {
+ return workQueue.size() == nextPos && !streamClosed;
+ }
+
+ public Object next() {
+ synchronized (workQueue) {
+ return workQueue.get(++lastPos);
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ public Iterator iterator() {
+ return new BlockingIterator();
+ }
+
+ /**
+ * Unsupported. Use {@link #iterator()} instead.
+ */
+ public int size() {
+ throw new UnsupportedOperationException("use method iterator()");
+ }
+
+ /**
+ * Unsupported. Use {@link #iterator()} instead.
+ */
+ public Class[] getLocatedClasses() {
+ throw new UnsupportedOperationException("use method iterator()");
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("LazyTestsToRun ");
+ synchronized (workQueue) {
+ sb.append("(more items expected: ").append(!streamClosed).append("): ");
+ sb.append(workQueue);
+ }
+
+ return sb.toString();
+ }
+
+}
View
1  surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
@@ -46,4 +46,5 @@
String TEST_SUITE_XML_FILES = "testSuiteXmlFiles";
String PROVIDER_CONFIGURATION = "providerConfiguration";
String FORKTESTSET = "forkTestSet";
+ String FORKTESTSET_PREFER_TESTS_FROM_IN_STREAM = "preferTestsFromInStream";
}
View
5 surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -61,7 +61,10 @@ public ProviderConfiguration deserialize()
final File reportsDirectory = new File( properties.getProperty( REPORTSDIRECTORY ) );
final String testNgVersion = properties.getProperty( TESTARTIFACT_VERSION );
final String testArtifactClassifier = properties.getProperty( TESTARTIFACT_CLASSIFIER );
+
final TypeEncodedValue typeEncodedTestForFork = properties.getTypeEncodedValue( FORKTESTSET );
+ final boolean preferTestsFromInStream = properties.getBooleanProperty( FORKTESTSET_PREFER_TESTS_FROM_IN_STREAM );
+
final String requestedTest = properties.getProperty( REQUESTEDTEST );
final String requestedTestMethod = properties.getProperty( REQUESTEDTESTMETHOD );
final File sourceDirectory = properties.getFileProperty( SOURCE_DIRECTORY );
@@ -90,7 +93,7 @@ public ProviderConfiguration deserialize()
return new ProviderConfiguration( dirScannerParams, runOrderParameters,
properties.getBooleanProperty( FAILIFNOTESTS ), reporterConfiguration, testNg,
- testSuiteDefinition, properties.getProperties(), typeEncodedTestForFork );
+ testSuiteDefinition, properties.getProperties(), typeEncodedTestForFork, preferTestsFromInStream );
}
public StartupConfiguration getProviderConfiguration()
View
15 surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -23,7 +23,9 @@
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PrintStream;
+
import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.util.LazyTestsToRun;
/**
* The part of the booter that is unique to a forked vm.
@@ -64,6 +66,7 @@ public static void main( String[] args )
final StartupConfiguration startupConfiguration = booterDeserializer.getProviderConfiguration();
TypeEncodedValue forkedTestSet = providerConfiguration.getTestForFork();
+ boolean readTestsFromInputStream = providerConfiguration.isReadTestsFromInStream();
final ClasspathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();
final ClassLoader testClassLoader = classpathConfiguration.createForkingTestClassLoader(
@@ -71,7 +74,17 @@ public static void main( String[] args )
startupConfiguration.writeSurefireTestClasspathProperty();
- Object testSet = forkedTestSet != null ? forkedTestSet.getDecodedValue( testClassLoader ) : null;
+ Object testSet;
+ if (forkedTestSet != null) {
+ testSet = forkedTestSet.getDecodedValue( testClassLoader );
+ }
+ else if (readTestsFromInputStream) {
+ testSet = new LazyTestsToRun(System.in, testClassLoader, originalOut);
+ }
+ else {
+ testSet = null;
+ }
+
runSuitesInProcess( testSet, testClassLoader, startupConfiguration, providerConfiguration, originalOut );
// Say bye.
originalOut.println( "Z,0,BYE!" );
View
12 surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
@@ -64,12 +64,14 @@
private final boolean failIfNoTests;
private final TypeEncodedValue forkTestSet;
+
+ private final boolean readTestsFromInStream;
public ProviderConfiguration( DirectoryScannerParameters directoryScannerParameters,
RunOrderParameters runOrderParameters, boolean failIfNoTests,
ReporterConfiguration reporterConfiguration, TestArtifactInfo testArtifact,
TestRequest testSuiteDefinition, Properties providerProperties,
- TypeEncodedValue typeEncodedTestSet )
+ TypeEncodedValue typeEncodedTestSet, boolean readTestsFromInStream)
{
this.runOrderParameters = runOrderParameters;
this.providerProperties = providerProperties;
@@ -79,6 +81,7 @@ public ProviderConfiguration( DirectoryScannerParameters directoryScannerParamet
this.dirScannerParams = directoryScannerParameters;
this.failIfNoTests = failIfNoTests;
this.forkTestSet = typeEncodedTestSet;
+ this.readTestsFromInStream = readTestsFromInStream;
}
@@ -133,9 +136,14 @@ public TypeEncodedValue getTestForFork()
{
return forkTestSet;
}
-
+
public RunOrderParameters getRunOrderParameters()
{
return runOrderParameters;
}
+
+
+ public boolean isReadTestsFromInStream() {
+ return readTestsFromInStream;
+ }
}
View
24 surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ForkModeIT.java
@@ -19,6 +19,10 @@
* under the License.
*/
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.maven.surefire.its.fixture.OutputValidator;
import org.apache.maven.surefire.its.fixture.SurefireIntegrationTestCase;
import org.apache.maven.surefire.its.fixture.SurefireLauncher;
@@ -55,8 +59,25 @@ public void testForkModeNone()
String[] pids = doTest( unpack( getProject() ).forkMode( "none" ) );
assertSamePids( pids );
}
+
+ public void testForkModeOncePerThreadSingleThread()
+ {
+ String[] pids = doTest( unpack( getProject() ).forkOncePerThread().threadCount(1) );
+ assertSamePids( pids );
+ }
+
+ public void testForkModeOncePerThreadTwoThreads()
+ {
+ String[] pids = doTest( unpack( getProject() ).forkOncePerThread().threadCount(2) );
+ assertDifferentPids( pids, 2 );
+ }
+
+ private void assertDifferentPids(String[] pids, int numOfDifferentPids) {
+ Set<String> pidSet = new HashSet<String>(Arrays.asList(pids));
+ assertEquals( "number of different pids is not as expected", numOfDifferentPids, pidSet.size() );
+ }
- public void testForkModeOnce()
+ public void testForkModeOnce()
{
String[] pids = doTest( unpack( getProject() ).forkOnce() );
// DGF It would be nice to assert that "once" was different
@@ -92,6 +113,7 @@ private void assertDifferentPids( String[] pids )
private String[] doTest( SurefireLauncher forkMode )
{
+ forkMode.addD( "testProperty", "testValue_${surefire.threadNumber}" );
final OutputValidator outputValidator = forkMode.executeTest();
outputValidator.verifyErrorFreeLog().assertTestSuiteResults( 3, 0, 0, 0 );
String[] pids = new String[3];
View
10 surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
@@ -384,6 +384,16 @@ public SurefireLauncher forkPerThread()
return forkMode( "perthread" );
}
+ public SurefireLauncher forkOncePerThread()
+ {
+ return forkMode( "onceperthread" );
+ }
+
+ public SurefireLauncher threadCount(int threadCount)
+ {
+ return addGoal( "-DthreadCount=" + threadCount );
+ }
+
public SurefireLauncher forkMode( String forkMode )
{
return addGoal( "-DforkMode=" + forkMode );
View
3  ...on-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire907PerThreadWithoutThreadCountIT.java
@@ -19,7 +19,6 @@
*/
import org.apache.maven.surefire.its.fixture.OutputValidator;
import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
-import org.apache.maven.surefire.its.fixture.SurefireLauncher;
import org.junit.Test;
@@ -30,7 +29,7 @@
public void categoryAB()
{
OutputValidator validator = unpack("fork-mode").forkPerThread().executeTestWithFailure();
- validator.verifyTextInLog( "Fork mode perthread requires a thread count" );
+ validator.verifyTextInLog( "Fork modes perthread and onceperthread require a thread count" );
}
}
View
1  surefire-integration-tests/src/test/resources/fork-mode-testng/pom.xml
@@ -26,6 +26,7 @@
<version>${surefire.version}</version>
<configuration>
<forkMode>${forkMode}</forkMode>
+ <threadCount>${threadCount}</threadCount>
</configuration>
</plugin>
</plugins>
View
5 surefire-integration-tests/src/test/resources/fork-mode-testng/src/test/java/forkMode/Test1.java
@@ -4,12 +4,15 @@
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.util.Random;
import org.testng.annotations.Test;
public class Test1
{
+ private static final Random RANDOM = new Random();
+
@Test
public void test1()
throws IOException
@@ -32,6 +35,8 @@ public static void dumpPidFile( String name )
// 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();
}
View
1  surefire-integration-tests/src/test/resources/fork-mode/pom.xml
@@ -42,6 +42,7 @@
<version>${surefire.version}</version>
<configuration>
<forkMode>${forkMode}</forkMode>
+ <threadCount>${threadCount}</threadCount>
</configuration>
</plugin>
</plugins>
View
7 surefire-integration-tests/src/test/resources/fork-mode/src/test/java/forkMode/Test1.java
@@ -4,6 +4,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.util.Random;
import junit.framework.TestCase;
@@ -11,7 +12,9 @@
extends TestCase
{
- public void test1()
+ private static final Random RANDOM = new Random();
+
+ public void test1()
throws IOException
{
dumpPidFile( this );
@@ -32,6 +35,8 @@ public static void dumpPidFile( TestCase test )
// 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();
}
View
12 surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
@@ -76,7 +76,17 @@ public RunResult invoke( Object forkTestSet )
{
if ( testsToRun == null )
{
- testsToRun = forkTestSet == null ? scanClassPath() : TestsToRun.fromClass( (Class<?>) forkTestSet );
+ if (forkTestSet instanceof TestsToRun)
+ {
+ testsToRun = (TestsToRun) forkTestSet;
+ }
+ else if (forkTestSet instanceof Class)
+ {
+ testsToRun = TestsToRun.fromClass( (Class<?>) forkTestSet );
+ } else
+ {
+ testsToRun = scanClassPath();
+ }
}
ReporterFactory reporterFactory = providerParameters.getReporterFactory();
View
18 surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -89,9 +89,19 @@ public RunResult invoke( Object forkTestSet )
{
if ( testsToRun == null )
{
- testsToRun = forkTestSet == null ? scanClassPath() : TestsToRun.fromClass( (Class<?>) forkTestSet );
+ if (forkTestSet instanceof TestsToRun)
+ {
+ testsToRun = (TestsToRun) forkTestSet;
+ }
+ else if (forkTestSet instanceof Class)
+ {
+ testsToRun = TestsToRun.fromClass( (Class) forkTestSet );
+ } else
+ {
+ testsToRun = scanClassPath();
+ }
}
-
+
upgradeCheck();
final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
@@ -107,9 +117,9 @@ public RunResult invoke( Object forkTestSet )
runNotifer.fireTestRunStarted( null );
- for ( Class<?> clazz : testsToRun.getLocatedClasses() )
+ for ( Iterator<Class<?>> iter = testsToRun.iterator(); iter.hasNext(); )
{
- executeTestSet( clazz, reporter, runNotifer );
+ executeTestSet( iter.next(), reporter, runNotifer );
}
runNotifer.fireTestRunFinished( result );
View
17 ...fire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
@@ -116,12 +116,17 @@ public RunResult invoke( Object forkTestSet )
if ( testsToRun == null )
{
- testsToRun = forkTestSet == null ? getSuitesAsList( filter ) : TestsToRun.fromClass( (Class) forkTestSet );
- }
-
- if ( testsToRun.size() == 0 )
- {
- filter = null;
+ if (forkTestSet instanceof TestsToRun)
+ {
+ testsToRun = (TestsToRun) forkTestSet;
+ }
+ else if (forkTestSet instanceof Class)
+ {
+ testsToRun = TestsToRun.fromClass( (Class) forkTestSet );
+ } else
+ {
+ testsToRun = getSuitesAsList( filter );
+ }
}
final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>();
View
23 surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java
@@ -19,12 +19,13 @@
* under the License.
*/
+import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
+
import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
import org.apache.maven.surefire.testset.TestSetFailedException;
import org.apache.maven.surefire.util.TestsToRun;
-
import org.junit.runner.Computer;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
@@ -51,16 +52,20 @@ public static void execute( TestsToRun testsToRun, JUnitCoreParameters jUnitCore
junitCore.addListener( runListener );
}
- Request req = Request.classes( computer, testsToRun.getLocatedClasses() );
- if ( filter != null )
- {
- req = req.filterWith( filter );
- }
-
try
{
- final Result run = junitCore.run( req );
- JUnit4RunListener.rethrowAnyTestMechanismFailures( run );
+ Iterator classIter = testsToRun.iterator();
+ while (classIter.hasNext())
+ {
+ Request req = Request.classes( computer, new Class[]{ (Class) classIter.next() });
+ if ( filter != null )
+ {
+ req = req.filterWith( filter );
+ }
+
+ final Result run = junitCore.run( req );
+ JUnit4RunListener.rethrowAnyTestMechanismFailures( run );
+ }
}
finally
{
View
110 ...e-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGDirectoryTestSuite.java
@@ -40,6 +40,7 @@
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.LazyTestsToRun;
import org.apache.maven.surefire.util.RunOrderCalculator;
import org.apache.maven.surefire.util.ScanResult;
import org.apache.maven.surefire.util.TestsToRun;
@@ -56,7 +57,9 @@
private final ArtifactVersion version;
private final Map options;
-
+
+ private final Map junitOptions;
+
private final String testSourceDirectory;
private final File reportsDirectory;
@@ -68,6 +71,8 @@
private final String testMethodPattern;
private final RunOrderCalculator runOrderCalculator;
+
+ private final Class junitTestClass;
public TestNGDirectoryTestSuite( String testSourceDirectory, String artifactVersion, Properties confOptions,
File reportsDirectory, String testMethodPattern,
@@ -83,55 +88,77 @@ public TestNGDirectoryTestSuite( String testSourceDirectory, String artifactVers
this.scanResult = scanResult;
this.version = new DefaultArtifactVersion( artifactVersion );
this.testMethodPattern = testMethodPattern;
+ this.junitTestClass = findJUnitTestClass();
+ this.junitOptions = createJUnitOptions();
}
public void execute( TestsToRun testsToRun, ReporterFactory reporterManagerFactory )
throws ReporterException, TestSetFailedException
{
- if ( testsToRun.size() == 0 )
- {
- return;
- }
+ if ( testsToRun instanceof LazyTestsToRun )
+ {
+ executeLazy( testsToRun, reporterManagerFactory );
+ } else if ( testsToRun.size() > 1 )
+ {
+ executeMulti( testsToRun, reporterManagerFactory );
+ } else if ( testsToRun.size() == 1 )
+ {
+ Class testClass = (Class) testsToRun.iterator().next();
+ executeSingleClass( reporterManagerFactory, testClass );
+ }
+ }
- if ( testsToRun.size() > 1 )
- {
- executeMulti( testsToRun, reporterManagerFactory );
- return;
- }
+ private void executeSingleClass( ReporterFactory reporterManagerFactory, Class testClass ) throws TestSetFailedException {
+ this.options.put( "suitename", testClass.getName() );
- this.options.put( "suitename", testsToRun.getLocatedClasses()[0].getName() );
+ RunListener reporter = reporterManagerFactory.createReporter();
+ ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
- RunListener reporter = reporterManagerFactory.createReporter();
- ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
+ startTestSuite( reporter, this );
- startTestSuite( reporter, this );
+ final Map optionsToUse = isJUnitTest(testClass) ? junitOptions : options;
+
+ TestNGExecutor.run( new Class[]{ testClass }, testSourceDirectory, optionsToUse,
+ version, reporter, this, reportsDirectory, testMethodPattern );
- TestNGExecutor.run( new Class[]{ (Class) testsToRun.iterator().next() }, this.testSourceDirectory, this.options,
- this.version, reporter, this, reportsDirectory, testMethodPattern );
+ finishTestSuite( reporter, this );
+ }
- finishTestSuite( reporter, this );
+ public void executeLazy( TestsToRun testsToRun, ReporterFactory reporterFactory )
+ throws ReporterException, TestSetFailedException
+ {
+
+ for ( Iterator testClassIt = testsToRun.iterator(); testClassIt.hasNext(); )
+ {
+ Class c = (Class) testClassIt.next();
+ executeSingleClass(reporterFactory, c);
+ }
}
+ private Class findJUnitTestClass() {
+ Class junitTest;
+ try
+ {
+ junitTest = Class.forName( "junit.framework.Test" );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ junitTest = null;
+ }
+ return junitTest;
+ }
+
public void executeMulti( TestsToRun testsToRun, ReporterFactory reporterFactory )
throws ReporterException, TestSetFailedException
{
- Class junitTest;
- try
- {
- junitTest = Class.forName( "junit.framework.Test" );
- }
- catch ( ClassNotFoundException e )
- {
- junitTest = null;
- }
-
List testNgTestClasses = new ArrayList();
List junitTestClasses = new ArrayList();
- for ( Iterator it = testsToRun.iterator(); it.hasNext(); )
+ Class[] allClasses = testsToRun.getLocatedClasses();
+ for ( int i = 0; i < allClasses.length; i++)
{
- Class c = (Class) it.next();
- if ( junitTest != null && junitTest.isAssignableFrom( c ) )
+ Class c = allClasses[i];
+ if ( isJUnitTest(c) )
{
junitTestClasses.add( c );
}
@@ -156,29 +183,30 @@ public void executeMulti( TestsToRun testsToRun, ReporterFactory reporterFactory
Class[] testClasses = (Class[]) testNgTestClasses.toArray( new Class[testNgTestClasses.size()] );
- TestNGExecutor.run( testClasses, this.testSourceDirectory, this.options, this.version, reporterManager, this,
+ TestNGExecutor.run( testClasses, this.testSourceDirectory, options, version, reporterManager, this,
testNgReportsDirectory, testMethodPattern );
if ( junitTestClasses.size() > 0 )
{
testClasses = (Class[]) junitTestClasses.toArray( new Class[junitTestClasses.size()] );
- Map junitOptions = new HashMap();
- for ( Iterator it = this.options.keySet().iterator(); it.hasNext(); )
- {
- Object key = it.next();
- junitOptions.put( key, options.get( key ) );
- }
-
- junitOptions.put( "junit", Boolean.TRUE );
-
- TestNGExecutor.run( testClasses, this.testSourceDirectory, junitOptions, this.version, reporterManager,
+ TestNGExecutor.run( testClasses, testSourceDirectory, junitOptions, version, reporterManager,
this, junitReportsDirectory, testMethodPattern );
}
finishTestSuite( reporterManager, this );
}
+ private boolean isJUnitTest(Class c) {
+ return junitTestClass != null && junitTestClass.isAssignableFrom( c );
+ }
+
+ private Map createJUnitOptions() {
+ Map junitOptions = new HashMap(this.options);
+ junitOptions.put( "junit", Boolean.TRUE );
+ return junitOptions;
+ }
+
// single class test
public void execute( String testSetName, ReporterFactory reporterManagerFactory )
throws ReporterException, TestSetFailedException
View
12 surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
@@ -100,7 +100,17 @@ public RunResult invoke( Object forkTestSet )
{
if ( testsToRun == null )
{
- testsToRun = forkTestSet == null ? scanClassPath() : TestsToRun.fromClass( (Class) forkTestSet );
+ if (forkTestSet instanceof TestsToRun)
+ {
+ testsToRun = (TestsToRun) forkTestSet;
+ }
+ else if (forkTestSet instanceof Class)
+ {
+ testsToRun = TestsToRun.fromClass( (Class) forkTestSet );
+ } else
+ {
+ testsToRun = scanClassPath();
+ }
}
TestNGDirectoryTestSuite suite = getDirectorySuite();
suite.execute( testsToRun, reporterFactory );
Please sign in to comment.
Something went wrong with that request. Please try again.