You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2020/01/22 23:02:41 UTC
[maven-surefire] 01/12: [SUREFIRE-1658] TCP/IP Channel for forked
Surefire JVM. Extensions API and SPI. Polymorphism for remote and local
process communication.
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch maven2surefire-jvm-communication
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit aaeccca343d56473bdf7acf6c5e380ffb622630e
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Jul 6 17:51:13 2019 +0200
[SUREFIRE-1658] TCP/IP Channel for forked Surefire JVM. Extensions API and SPI. Polymorphism for remote and local process communication.
---
Jenkinsfile | 2 +-
.../maven/plugin/failsafe/IntegrationTestMojo.java | 10 +
maven-surefire-common/pom.xml | 16 --
.../plugin/surefire/AbstractSurefireMojo.java | 23 ++-
.../maven/plugin/surefire/CommonReflector.java | 18 +-
.../AbstractClasspathForkConfiguration.java | 6 +-
.../surefire/booterclient/BooterSerializer.java | 5 +-
.../booterclient/ClasspathForkConfiguration.java | 6 +-
.../booterclient/DefaultForkConfiguration.java | 13 +-
.../surefire/booterclient/ForkConfiguration.java | 2 +
.../plugin/surefire/booterclient/ForkStarter.java | 61 +++---
.../booterclient/JarManifestForkConfiguration.java | 6 +-
.../ModularClasspathForkConfiguration.java | 6 +-
...InputStream.java => AbstractCommandReader.java} | 16 +-
...ommandStream.java => DefaultCommandReader.java} | 60 ++----
.../DefferedChannelCommandSender.java | 14 +-
.../lazytestprovider/TestLessInputStream.java | 7 +-
.../lazytestprovider/TestProvidingInputStream.java | 14 +-
.../output/NativeStdErrStreamConsumer.java | 6 +-
.../output/NativeStdOutStreamConsumer.java | 28 ++-
.../output/ThreadedStreamConsumer.java | 12 +-
.../surefire/extensions/LegacyForkChannel.java | 31 ++-
.../surefire/extensions/LegacyForkNodeFactory.java | 19 +-
.../extensions/NetworkingProcessExecutor.java | 218 +++++++++++++++++++++
.../surefire/extensions/PipeProcessExecutor.java | 144 ++++++++++++++
.../plugin/surefire/extensions/StdErrAdapter.java | 25 ++-
.../plugin/surefire/extensions/StdOutAdapter.java | 25 ++-
.../surefire/extensions/SurefireForkChannel.java | 84 ++++++++
.../extensions/SurefireForkNodeFactory.java | 20 +-
.../AbstractSurefireMojoJava7PlusTest.java | 1 +
.../plugin/surefire/AbstractSurefireMojoTest.java | 1 +
.../maven/plugin/surefire/CommonReflectorTest.java | 50 +++++
.../maven/plugin/surefire/MojoMocklessTest.java | 7 +
.../plugin/surefire/SurefireReflectorTest.java | 71 -------
...ooterDeserializerProviderConfigurationTest.java | 3 +-
...BooterDeserializerStartupConfigurationTest.java | 3 +-
.../booterclient/DefaultForkConfigurationTest.java | 44 ++---
.../booterclient/ForkConfigurationTest.java | 10 +-
.../ModularClasspathForkConfigurationTest.java | 2 +-
.../TestLessInputStreamBuilderTest.java | 41 +++-
.../TestProvidingInputStreamTest.java | 150 ++++++++++----
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 2 -
.../maven/plugin/surefire/SurefirePlugin.java | 10 +
pom.xml | 6 +-
.../maven/surefire/booter/BaseProviderFactory.java | 63 +++---
.../org/apache/maven/surefire/booter/Command.java | 21 +-
...Aware.java => MasterProcessChannelEncoder.java} | 30 ++-
.../surefire/booter/MasterProcessCommand.java | 157 +++++----------
.../surefire/booter/RunOrderParametersAware.java | 30 ---
.../surefire/booter/TestArtifactInfoAware.java | 30 ---
.../maven/surefire/booter/TestRequestAware.java | 30 ---
.../CommandChainReader.java} | 19 +-
.../{booter => providerapi}/CommandListener.java | 4 +-
.../providerapi/MasterProcessChannelDecoder.java | 47 +++++
.../surefire/providerapi/ProviderParameters.java | 5 +-
.../maven/surefire/testset/TestListResolver.java | 2 +-
.../maven/surefire/util/ReflectionUtils.java | 19 --
.../util/internal/DaemonThreadFactory.java | 40 +---
.../java/org/apache/maven/JUnit4SuiteTest.java | 6 -
.../surefire/booter/MasterProcessCommandTest.java | 164 ----------------
surefire-booter/pom.xml | 51 ++++-
.../maven/surefire/booter/BooterConstants.java | 1 +
.../maven/surefire/booter/BooterDeserializer.java | 5 +
.../maven/surefire/booter/CommandReader.java | 113 +++++------
.../apache/maven/surefire/booter/ForkedBooter.java | 40 +++-
.../maven/surefire/booter/LazyTestsToRun.java | 10 +-
.../surefire/booter/ProviderConfiguration.java | 2 -
.../maven/surefire/booter/ProviderFactory.java | 4 +-
.../surefire/booter/StartupConfiguration.java | 5 +
.../maven/surefire/booter/SurefireReflector.java | 88 +++------
.../spi/DefaultMasterProcessChannelDecoder.java | 162 +++++++++++++++
.../DefaultMasterProcessChannelDecoderFactory.java | 27 ++-
...MasterProcessCommandNoMagicNumberException.java | 17 +-
.../spi/MasterProcessUnknownCommandException.java | 18 +-
...surefire.spi.MasterProcessChannelDecoderFactory | 19 ++
.../maven/surefire/booter/CommandReaderTest.java | 36 ++--
.../DefaultMasterProcessChannelDecoderTest.java | 148 ++++++++++++++
.../java/org/apache/maven/surefire/booter/Foo.java | 35 ++--
.../surefire/booter/ForkedBooterMockTest.java | 54 ++++-
.../surefire/booter/IsolatedClassLoaderTest.java | 66 +++++++
.../maven/surefire/booter/JUnit4SuiteTest.java | 4 +
.../surefire/booter/NewClassLoaderRunner.java | 0
.../surefire/booter/SurefireReflectorTest.java | 60 +++---
surefire-extensions-api/pom.xml | 38 ++--
.../maven/surefire/extensions/CommandReader.java | 23 ++-
.../maven/surefire/extensions/EventHandler.java | 13 +-
.../surefire/extensions/ExecutableCommandline.java | 18 +-
.../maven/surefire/extensions/ForkChannel.java | 27 ++-
.../maven/surefire/extensions/ForkNodeFactory.java | 21 +-
.../surefire/extensions/StdErrStreamLine.java | 8 +-
.../surefire/extensions/StdOutStreamLine.java | 10 +-
surefire-extensions-spi/pom.xml | 42 ++++
.../spi/MasterProcessChannelDecoderFactory.java | 23 ++-
.../maven/surefire/junit4/JUnit4Provider.java | 9 +-
.../maven/surefire/junit4/JUnit4ProviderTest.java | 2 +-
.../surefire/junitcore/JUnitCoreProvider.java | 9 +-
.../maven/surefire/junitcore/Surefire746Test.java | 3 +-
.../maven/surefire/testng/TestNGProvider.java | 9 +-
98 files changed, 2038 insertions(+), 1147 deletions(-)
diff --git a/Jenkinsfile b/Jenkinsfile
index c24a81d..ac8c07f 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -35,7 +35,7 @@ final def mavens = env.BRANCH_NAME == 'master' ? ['3.6.x', '3.2.x'] : ['3.6.x']
// all non-EOL versions and the first EA
final def jdks = [14, 13, 11, 8, 7]
-final def options = ['-e', '-V', '-B', '-nsu', '-P', 'run-its']
+final def options = ['-e', '-V', '-B', '-nsu', '-DskipTests', '-DskipITs']
final def goals = ['clean', 'install']
final def goalsDepl = ['clean', 'deploy', 'jacoco:report']
final Map stages = [:]
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
index e465bb2..a6771bc 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
@@ -27,6 +27,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.suite.RunResult;
import java.io.File;
@@ -384,6 +385,9 @@ public class IntegrationTestMojo
@Parameter( property = "failsafe.useModulePath", defaultValue = "true" )
private boolean useModulePath;
+ @Parameter( property = "failsafe.forkNode" )
+ private ForkNodeFactory forkNode;
+
/**
* You can selectively exclude individual environment variables by enumerating their keys.
* <br>
@@ -912,6 +916,12 @@ public class IntegrationTestMojo
}
@Override
+ protected final ForkNodeFactory getForkNode()
+ {
+ return forkNode;
+ }
+
+ @Override
protected final String[] getExcludedEnvironmentVariables()
{
return excludedEnvironmentVariables == null ? new String[0] : excludedEnvironmentVariables;
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index fefe831..8ab9e98 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -120,22 +120,6 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <id>build-test-classpath</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>build-classpath</goal>
- </goals>
- <configuration>
- <includeScope>test</includeScope>
- <outputFile>target/test-classpath/cp.txt</outputFile>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
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 b8a5297..5f2663b 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
@@ -26,6 +26,7 @@ import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter;
+import org.apache.maven.plugin.surefire.extensions.SurefireForkNodeFactory;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
import org.apache.maven.plugins.annotations.Component;
@@ -73,6 +74,7 @@ import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
import org.apache.maven.surefire.booter.SurefireExecutionException;
import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.suite.RunResult;
@@ -831,6 +833,8 @@ public abstract class AbstractSurefireMojo
protected abstract String getEnableProcessChecker();
+ protected abstract ForkNodeFactory getForkNode();
+
/**
* This plugin MOJO artifact.
*
@@ -2254,6 +2258,14 @@ public abstract class AbstractSurefireMojo
getConsoleLogger() );
}
+ // todo this is in separate method and can be better tested than whole method createForkConfiguration()
+ @Nonnull
+ private ForkNodeFactory getForkNodeFactory()
+ {
+ ForkNodeFactory forkNode = getForkNode();
+ return forkNode == null ? new SurefireForkNodeFactory() : forkNode;
+ }
+
@Nonnull
private ForkConfiguration createForkConfiguration( Platform platform )
{
@@ -2263,6 +2275,8 @@ public abstract class AbstractSurefireMojo
Classpath bootClasspath = getArtifactClasspath( shadeFire != null ? shadeFire : surefireBooterArtifact );
+ ForkNodeFactory forkNode = getForkNodeFactory();
+
if ( canExecuteProviderWithModularPath( platform ) )
{
return new ModularClasspathForkConfiguration( bootClasspath,
@@ -2277,7 +2291,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
else if ( getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable() )
{
@@ -2293,7 +2308,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
else
{
@@ -2309,7 +2325,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
index 835fb89..466148f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
@@ -23,8 +23,8 @@ import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.booter.SurefireReflector;
import org.apache.maven.surefire.util.SurefireReflectionException;
import javax.annotation.Nonnull;
@@ -71,7 +71,7 @@ public class CommonReflector
{
Class<?>[] args = { this.startupReportConfiguration, this.consoleLogger };
Object src = createStartupReportConfiguration( startupReportConfiguration );
- Object logger = SurefireReflector.createConsoleLogger( consoleLogger, surefireClassLoader );
+ Object logger = createConsoleLogger( consoleLogger, surefireClassLoader );
Object[] params = { src, logger };
return instantiateObject( DefaultReporterFactory.class.getName(), args, params, surefireClassLoader );
}
@@ -84,7 +84,6 @@ public class CommonReflector
int.class, String.class, String.class, boolean.class,
statelessTestsetReporter, consoleOutputReporter,
statelessTestsetInfoReporter );
- //noinspection BooleanConstructorCall
Object[] params = { reporterConfiguration.isUseFile(), reporterConfiguration.isPrintSummary(),
reporterConfiguration.getReportFormat(), reporterConfiguration.isRedirectTestOutputToFile(),
reporterConfiguration.getReportsDirectory(),
@@ -98,4 +97,17 @@ public class CommonReflector
};
return newInstance( constructor, params );
}
+
+ static Object createConsoleLogger( ConsoleLogger consoleLogger, ClassLoader cl )
+ {
+ try
+ {
+ Class<?> decoratorClass = cl.loadClass( ConsoleLoggerDecorator.class.getName() );
+ return getConstructor( decoratorClass, Object.class ).newInstance( consoleLogger );
+ }
+ catch ( Exception e )
+ {
+ throw new SurefireReflectionException( e );
+ }
+ }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
index 692f486..08a8373 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
@@ -21,6 +21,7 @@ package org.apache.maven.plugin.surefire.booterclient;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -49,10 +50,11 @@ abstract class AbstractClasspathForkConfiguration
int forkCount,
boolean reuseForks,
@Nonnull Platform pluginPlatform,
- @Nonnull ConsoleLogger log )
+ @Nonnull ConsoleLogger log,
+ @Nonnull ForkNodeFactory forkNodeFactory )
{
super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
- environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+ environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory );
}
@Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
index 7eacb74..b166cc2 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
@@ -71,6 +71,7 @@ import static org.apache.maven.surefire.booter.BooterConstants.TESTARTIFACT_CLAS
import static org.apache.maven.surefire.booter.BooterConstants.TESTARTIFACT_VERSION;
import static org.apache.maven.surefire.booter.BooterConstants.USEMANIFESTONLYJAR;
import static org.apache.maven.surefire.booter.BooterConstants.USESYSTEMCLASSLOADER;
+import static org.apache.maven.surefire.booter.BooterConstants.FORK_NODE_CONNECTION_STRING;
import static org.apache.maven.surefire.booter.SystemPropertyManager.writePropertiesFile;
/**
@@ -102,11 +103,11 @@ class BooterSerializer
*/
File serialize( KeyValueSource sourceProperties, ProviderConfiguration providerConfiguration,
StartupConfiguration startupConfiguration, Object testSet, boolean readTestsFromInStream,
- Long pid, int forkNumber )
+ Long pid, int forkNumber, String forkNodeConnectionString )
throws IOException
{
SurefireProperties properties = new SurefireProperties( sourceProperties );
-
+ properties.setProperty( FORK_NODE_CONNECTION_STRING, forkNodeConnectionString );
properties.setProperty( PLUGIN_PID, pid );
AbstractPathConfiguration cp = startupConfiguration.getClasspathConfiguration();
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
index 1ca3932..94b7ee3 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
@@ -24,6 +24,7 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -48,10 +49,11 @@ public final class ClasspathForkConfiguration
@Nonnull String[] excludedEnvironmentVariables,
boolean debug, int forkCount,
boolean reuseForks, @Nonnull Platform pluginPlatform,
- @Nonnull ConsoleLogger log )
+ @Nonnull ConsoleLogger log,
+ @Nonnull ForkNodeFactory forkNodeFactory )
{
super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
- environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+ environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory );
}
@Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
index 4ab4435..443bf45 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
@@ -26,6 +26,7 @@ import org.apache.maven.surefire.booter.AbstractPathConfiguration;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.util.internal.ImmutableMap;
import javax.annotation.Nonnull;
@@ -65,6 +66,7 @@ public abstract class DefaultForkConfiguration
private final boolean reuseForks;
@Nonnull private final Platform pluginPlatform;
@Nonnull private final ConsoleLogger log;
+ @Nonnull private final ForkNodeFactory forkNodeFactory;
@SuppressWarnings( "checkstyle:parameternumber" )
protected DefaultForkConfiguration( @Nonnull Classpath booterClasspath,
@@ -79,7 +81,8 @@ public abstract class DefaultForkConfiguration
int forkCount,
boolean reuseForks,
@Nonnull Platform pluginPlatform,
- @Nonnull ConsoleLogger log )
+ @Nonnull ConsoleLogger log,
+ @Nonnull ForkNodeFactory forkNodeFactory )
{
this.booterClasspath = booterClasspath;
this.tempDirectory = tempDirectory;
@@ -94,6 +97,7 @@ public abstract class DefaultForkConfiguration
this.reuseForks = reuseForks;
this.pluginPlatform = pluginPlatform;
this.log = log;
+ this.forkNodeFactory = forkNodeFactory;
}
protected abstract void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@@ -108,6 +112,13 @@ public abstract class DefaultForkConfiguration
return jvmArgLine;
}
+ @Nonnull
+ @Override
+ public final ForkNodeFactory getForkNodeFactory()
+ {
+ return forkNodeFactory;
+ }
+
/**
* @param config The startup configuration
* @param forkNumber index of forked JVM, to be the replacement in the argLine
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 92bebd0..9fddf96 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
@@ -25,6 +25,7 @@ import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ForkedBooter;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -39,6 +40,7 @@ public abstract class ForkConfiguration
{
static final String DEFAULT_PROVIDER_CLASS = ForkedBooter.class.getName();
+ @Nonnull public abstract ForkNodeFactory getForkNodeFactory();
@Nonnull public abstract File getTempDirectory();
@Nullable protected abstract String getDebugLine();
@Nonnull protected abstract File getWorkingDirectory();
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 0ba2f46..73340a8 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,7 @@ package org.apache.maven.plugin.surefire.booterclient;
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.AbstractForkInputStream;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.AbstractCommandReader;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
@@ -38,7 +38,6 @@ import org.apache.maven.surefire.extensions.util.CommandlineStreams;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
import org.apache.maven.surefire.extensions.util.LineConsumerThread;
import org.apache.maven.surefire.extensions.util.StreamFeeder;
-import org.apache.maven.surefire.shared.utils.cli.CommandLineException;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
@@ -47,6 +46,8 @@ import org.apache.maven.surefire.booter.Shutdown;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
import org.apache.maven.surefire.booter.SurefireExecutionException;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.suite.RunResult;
@@ -79,7 +80,6 @@ import static java.lang.StrictMath.min;
import static java.lang.System.currentTimeMillis;
import static java.lang.Thread.currentThread;
import static java.util.Collections.addAll;
-import static java.util.Objects.requireNonNull;
import static java.util.concurrent.Executors.newScheduledThreadPool;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -192,7 +192,7 @@ public class ForkStarter
{
closeable.close();
}
- catch ( IOException e )
+ catch ( IOException | RuntimeException e )
{
// This error does not fail a test and does not necessarily mean that the forked JVM std/out stream
// was not closed, see ThreadedStreamConsumer. This error means that JVM wrote messages to a native
@@ -212,11 +212,17 @@ public class ForkStarter
@Override
public void close()
{
- run();
- testProvidingInputStream.clear();
- if ( inputStreamCloserHook != null )
+ try
+ {
+ run();
+ }
+ finally
{
- removeShutdownHook( inputStreamCloserHook );
+ testProvidingInputStream.clear();
+ if ( inputStreamCloserHook != null )
+ {
+ removeShutdownHook( inputStreamCloserHook );
+ }
}
}
@@ -289,7 +295,8 @@ public class ForkStarter
defaultReporterFactories.add( forkedReporterFactory );
ForkClient forkClient =
new ForkClient( forkedReporterFactory, stream, log, new AtomicBoolean(), forkNumber );
- return fork( null, props, forkClient, effectiveSystemProperties, forkNumber, stream, false );
+ return fork( null, props, forkClient, effectiveSystemProperties, forkNumber, stream,
+ forkConfiguration.getForkNodeFactory(), false );
}
finally
{
@@ -379,7 +386,8 @@ public class ForkStarter
try
{
return fork( null, new PropertiesWrapper( providerProperties ), forkClient,
- effectiveSystemProperties, forkNumber, testProvidingInputStream, true );
+ effectiveSystemProperties, forkNumber, testProvidingInputStream,
+ forkConfiguration.getForkNodeFactory(), true );
}
finally
{
@@ -453,7 +461,8 @@ public class ForkStarter
{
return fork( testSet,
new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
- forkClient, effectiveSystemProperties, forkNumber, stream, false );
+ forkClient, effectiveSystemProperties, forkNumber, stream,
+ forkConfiguration.getForkNodeFactory(), false );
}
finally
{
@@ -549,21 +558,25 @@ public class ForkStarter
private RunResult fork( Object testSet, PropertiesWrapper providerProperties, ForkClient forkClient,
SurefireProperties effectiveSystemProperties, int forkNumber,
- AbstractForkInputStream commandInputStream, boolean readTestsFromInStream )
+ AbstractCommandReader commandReader, ForkNodeFactory forkNodeFactory,
+ boolean readTestsFromInStream )
throws SurefireBooterForkException
{
final String tempDir;
final File surefireProperties;
final File systPropsFile;
+ final ForkChannel forkChannel;
try
{
+ forkChannel = forkNodeFactory.createForkChannel();
tempDir = forkConfiguration.getTempDirectory().getCanonicalPath();
BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
Long pluginPid = forkConfiguration.getPluginPlatform().getPluginPid();
- surefireProperties = booterSerializer.serialize( providerProperties, providerConfiguration,
- startupConfiguration, testSet, readTestsFromInStream, pluginPid, forkNumber );
-
log.debug( "Determined Maven Process ID " + pluginPid );
+ String connectionString = forkChannel.getForkNodeConnectionString();
+ log.debug( "Fork Channel [" + forkNumber + "] connection string " + connectionString );
+ surefireProperties = booterSerializer.serialize( providerProperties, providerConfiguration,
+ startupConfiguration, testSet, readTestsFromInStream, pluginPid, forkNumber, connectionString );
if ( effectiveSystemProperties != null )
{
@@ -588,10 +601,7 @@ public class ForkStarter
OutputStreamFlushableCommandline cli =
forkConfiguration.createCommandLine( startupConfiguration, forkNumber, dumpLogDir );
- if ( commandInputStream != null )
- {
- commandInputStream.setFlushReceiverProvider( cli );
- }
+ commandReader.setFlushReceiverProvider( cli );
cli.createArg().setValue( tempDir );
cli.createArg().setValue( DUMP_FILE_PREFIX + forkNumber );
@@ -602,7 +612,7 @@ public class ForkStarter
}
ThreadedStreamConsumer eventConsumer = new ThreadedStreamConsumer( forkClient );
- CloseableCloser closer = new CloseableCloser( forkNumber, eventConsumer, requireNonNull( commandInputStream ) );
+ CloseableCloser closer = new CloseableCloser( forkNumber, eventConsumer, commandReader );
log.debug( "Forking command line: " + cli );
@@ -615,6 +625,8 @@ public class ForkStarter
DefaultReporterFactory reporter = forkClient.getDefaultReporterFactory();
currentForkClients.add( forkClient );
CountdownCloseable countdownCloseable = new CountdownCloseable( eventConsumer, 2 );
+ //todo implement extension: forkChannel.createExecutableCommandline()
+ //todo implement extension: executableCommandline.executeCommandLineAsCallable(...)
try ( CommandlineExecutor exec = new CommandlineExecutor( cli, countdownCloseable ) )
{
// default impl of the extension - solves everything including the encoder/decoder, Process starter,
@@ -623,7 +635,7 @@ public class ForkStarter
// BEGIN: beginning of the call of the extension
CommandlineStreams streams = exec.execute();
closer.addCloseable( streams );
- in = new StreamFeeder( "std-in-fork-" + forkNumber, streams.getStdInChannel(), commandInputStream );
+ in = new StreamFeeder( "std-in-fork-" + forkNumber, streams.getStdInChannel(), commandReader );
in.start();
out = new LineConsumerThread( "std-out-fork-" + forkNumber, streams.getStdOutChannel(),
eventConsumer, countdownCloseable );
@@ -652,8 +664,9 @@ public class ForkStarter
out.disable();
err.disable();
}
- catch ( CommandLineException e )
+ catch ( Exception e )
{
+ // CommandLineException from pipes and IOException from sockets
runResult = failure( reporter.getGlobalRunStatistics().getRunResult(), e );
String cliErr = e.getLocalizedMessage();
Throwable cause = e.getCause();
@@ -665,7 +678,7 @@ public class ForkStarter
currentForkClients.remove( forkClient );
try
{
- Closeable c = forkClient.isSaidGoodBye() ? closer : commandInputStream;
+ Closeable c = forkClient.isSaidGoodBye() ? closer : commandReader;
c.close();
}
catch ( IOException e )
@@ -710,7 +723,7 @@ public class ForkStarter
//noinspection ThrowFromFinallyBlock
throw new SurefireBooterForkException( "There was an error in the forked process"
+ detail
- + ( stackTrace == null ? "" : stackTrace ), cause );
+ + ( stackTrace == null ? "" : "\n" + stackTrace ), cause );
}
if ( !forkClient.isSaidGoodBye() )
{
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
index 02c275c..281118b 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
@@ -28,6 +28,7 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -70,10 +71,11 @@ public final class JarManifestForkConfiguration
@Nonnull String[] excludedEnvironmentVariables,
boolean debug,
int forkCount, boolean reuseForks, @Nonnull Platform pluginPlatform,
- @Nonnull ConsoleLogger log )
+ @Nonnull ConsoleLogger log,
+ @Nonnull ForkNodeFactory forkNodeFactory )
{
super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
- environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+ environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory );
}
@Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
index 8f5030b..67a977c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
@@ -28,6 +28,7 @@ import org.apache.maven.surefire.booter.ModularClasspath;
import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -67,10 +68,11 @@ public class ModularClasspathForkConfiguration
@Nonnegative int forkCount,
boolean reuseForks,
@Nonnull Platform pluginPlatform,
- @Nonnull ConsoleLogger log )
+ @Nonnull ConsoleLogger log,
+ @Nonnull ForkNodeFactory forkNodeFactory )
{
super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
- environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+ environmentVariables, excludedEnvironmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory );
}
@Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractForkInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandReader.java
similarity index 84%
rename from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractForkInputStream.java
rename to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandReader.java
index a884c15..a31e9f7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractForkInputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandReader.java
@@ -19,32 +19,34 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
* under the License.
*/
+import org.apache.maven.surefire.extensions.CommandReader;
+
import java.io.IOException;
-import java.io.InputStream;
import static java.util.Objects.requireNonNull;
/**
- * Reader stream sends bytes to forked jvm std-{@link InputStream input-stream}.
+ * Stream reader returns bytes which ar finally sent to the forked jvm std-input-stream.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
-public abstract class AbstractForkInputStream
- extends InputStream
- implements NotifiableTestStream
+public abstract class AbstractCommandReader
+ implements CommandReader, DefferedChannelCommandSender
{
private volatile FlushReceiverProvider flushReceiverProvider;
/**
* @param flushReceiverProvider the provider for a flush receiver.
*/
+ @Override
public void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider )
{
this.flushReceiverProvider = requireNonNull( flushReceiverProvider );
}
- protected boolean tryFlush()
+ @Override
+ public void tryFlush()
throws IOException
{
if ( flushReceiverProvider != null )
@@ -53,9 +55,7 @@ public abstract class AbstractForkInputStream
if ( flushReceiver != null )
{
flushReceiver.flush();
- return true;
}
}
- return false;
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefaultCommandReader.java
similarity index 63%
rename from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandStream.java
rename to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefaultCommandReader.java
index 31b56c4..9aa19c3 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/AbstractCommandStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefaultCommandReader.java
@@ -20,7 +20,6 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.MasterProcessCommand;
import java.io.IOException;
@@ -31,14 +30,9 @@ import java.io.IOException;
* @since 2.19
* @see org.apache.maven.surefire.booter.Command
*/
-public abstract class AbstractCommandStream
- extends AbstractForkInputStream
+public abstract class DefaultCommandReader
+ extends AbstractCommandReader
{
- private byte[] currentBuffer;
- private int currentPos;
-
- protected abstract boolean isClosed();
-
/**
* Opposite to {@link #isClosed()}.
* @return {@code true} if not closed
@@ -62,59 +56,35 @@ public abstract class AbstractCommandStream
protected abstract Command nextCommand();
/**
- * Returns quietly and immediately.
- */
- protected final void invalidateInternalBuffer()
- {
- currentBuffer = null;
- currentPos = 0;
- }
-
- /**
* Used by single thread in StreamFeeder class.
*
* @return {@inheritDoc}
* @throws IOException {@inheritDoc}
*/
- @SuppressWarnings( "checkstyle:magicnumber" )
@Override
- public int read()
+ public Command readNextCommand()
throws IOException
{
+ tryFlush();
+
if ( isClosed() )
{
- tryFlush();
- return -1;
+ return null;
}
- if ( currentBuffer == null )
+ if ( !canContinue() )
{
- tryFlush();
-
- if ( !canContinue() )
- {
- close();
- return -1;
- }
-
- beforeNextCommand();
-
- if ( isClosed() )
- {
- return -1;
- }
-
- Command cmd = nextCommand();
- MasterProcessCommand cmdType = cmd.getCommandType();
- currentBuffer = cmdType.hasDataType() ? cmdType.encode( cmd.getData() ) : cmdType.encode();
+ close();
+ return null;
}
- int b = currentBuffer[currentPos++] & 0xff;
- if ( currentPos == currentBuffer.length )
+ beforeNextCommand();
+
+ if ( isClosed() )
{
- currentBuffer = null;
- currentPos = 0;
+ return null;
}
- return b;
+
+ return nextCommand();
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefferedChannelCommandSender.java
similarity index 66%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java
rename to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefferedChannelCommandSender.java
index 0bfcdb8..e489caa 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefferedChannelCommandSender.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,17 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import java.io.Closeable;
+
/**
- * See the plugin configuration parameter {@code shutdown}.
+ * Physical implementation of command sender.<br>
+ * Instance of {@link AbstractCommandReader} (namely {@link TestLessInputStream} or {@link TestProvidingInputStream}).
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-public interface ShutdownAware
+public interface DefferedChannelCommandSender
+ extends NotifiableTestStream, Closeable
{
- void setShutdown( Shutdown shutdown );
+ void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider );
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
index 372ce00..a1060a7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
@@ -45,7 +45,7 @@ import static org.apache.maven.surefire.booter.Command.toShutdown;
* @since 2.19
*/
public final class TestLessInputStream
- extends AbstractCommandStream
+ extends DefaultCommandReader
{
private final Semaphore barrier = new Semaphore( 0 );
@@ -108,7 +108,7 @@ public final class TestLessInputStream
}
@Override
- protected boolean isClosed()
+ public boolean isClosed()
{
return closed.get();
}
@@ -141,7 +141,6 @@ public final class TestLessInputStream
{
if ( closed.compareAndSet( false, true ) )
{
- invalidateInternalBuffer();
barrier.drainPermits();
barrier.release();
}
@@ -166,8 +165,6 @@ public final class TestLessInputStream
}
catch ( InterruptedException e )
{
- // help GC to free this object because StreamFeeder Thread cannot read it anyway after IOE
- invalidateInternalBuffer();
throw new IOException( e.getLocalizedMessage() );
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
index a4255cc..6f3a4de 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java
@@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.maven.surefire.booter.Command.BYE_ACK;
import static org.apache.maven.surefire.booter.Command.NOOP;
import static org.apache.maven.surefire.booter.Command.SKIP_SINCE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.Command.TEST_SET_FINISHED;
import static org.apache.maven.surefire.booter.Command.toRunClass;
import static org.apache.maven.surefire.booter.Command.toShutdown;
@@ -50,7 +51,7 @@ import static org.apache.maven.surefire.booter.Command.toShutdown;
* @author Tibor Digana (tibor17)
*/
public final class TestProvidingInputStream
- extends AbstractCommandStream
+ extends DefaultCommandReader
{
private final Semaphore barrier = new Semaphore( 0 );
@@ -77,7 +78,7 @@ public final class TestProvidingInputStream
{
if ( canContinue() )
{
- commands.add( Command.TEST_SET_FINISHED );
+ commands.add( TEST_SET_FINISHED );
barrier.release();
}
}
@@ -129,7 +130,7 @@ public final class TestProvidingInputStream
if ( cmd == null )
{
String cmdData = testClassNames.poll();
- return cmdData == null ? Command.TEST_SET_FINISHED : toRunClass( cmdData );
+ return cmdData == null ? TEST_SET_FINISHED : toRunClass( cmdData );
}
else
{
@@ -145,7 +146,7 @@ public final class TestProvidingInputStream
}
@Override
- protected boolean isClosed()
+ public boolean isClosed()
{
return closed.get();
}
@@ -167,7 +168,6 @@ public final class TestProvidingInputStream
{
if ( closed.compareAndSet( false, true ) )
{
- invalidateInternalBuffer();
barrier.drainPermits();
barrier.release();
}
@@ -182,9 +182,7 @@ public final class TestProvidingInputStream
}
catch ( InterruptedException e )
{
- // help GC to free this object because StreamFeeder Thread cannot read it anyway after IOE
- invalidateInternalBuffer();
- throw new IOException( e.getLocalizedMessage() );
+ throw new IOException( e.getLocalizedMessage(), e );
}
}
}
\ No newline at end of file
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
index b17bfe4..6082096 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
@@ -20,7 +20,7 @@ package org.apache.maven.plugin.surefire.booterclient.output;
*/
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
+import org.apache.maven.surefire.extensions.StdErrStreamLine;
/**
* Used by forked JMV, see {@link org.apache.maven.plugin.surefire.booterclient.ForkStarter}.
@@ -30,7 +30,7 @@ import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
* @see org.apache.maven.plugin.surefire.booterclient.ForkStarter
*/
public final class NativeStdErrStreamConsumer
- implements StreamConsumer
+ implements StdErrStreamLine
{
private final DefaultReporterFactory defaultReporterFactory;
@@ -40,7 +40,7 @@ public final class NativeStdErrStreamConsumer
}
@Override
- public void consumeLine( String line )
+ public void handleLine( String line )
{
InPluginProcessDumpSingleton.getSingleton()
.dumpStreamText( line, defaultReporterFactory.getReportsDirectory() );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
similarity index 58%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
index eddebed..1f915ae 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -9,7 +9,7 @@ package org.apache.maven.surefire.booter;
* "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
+ * 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
@@ -19,17 +19,25 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.extensions.StdOutStreamLine;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+public class NativeStdOutStreamConsumer
+ implements StdOutStreamLine
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final ConsoleLogger logger;
+
+ public NativeStdOutStreamConsumer( ConsoleLogger logger )
+ {
+ this.logger = logger;
+ }
+
+ @Override
+ public void handleLine( String line )
+ {
+ logger.info( line );
+ }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumer.java
index 853d35c..b3c5c29 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumer.java
@@ -20,8 +20,10 @@ package org.apache.maven.plugin.surefire.booterclient.output;
*/
import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
+import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.util.internal.DaemonThreadFactory;
+import javax.annotation.Nonnull;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
@@ -36,7 +38,7 @@ import static java.lang.Thread.currentThread;
* @author Kristian Rosenvold
*/
public final class ThreadedStreamConsumer
- implements StreamConsumer, Closeable
+ implements EventHandler, StreamConsumer, Closeable
{
private static final String END_ITEM = "";
@@ -113,7 +115,13 @@ public final class ThreadedStreamConsumer
}
@Override
- public void consumeLine( String s )
+ public void handleEvent( @Nonnull String event )
+ {
+ consumeLine( event );
+ }
+
+ @Override
+ public void consumeLine( @Nonnull String s )
{
if ( stop.get() )
{
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
similarity index 57%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
index eddebed..28cad5a 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,32 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.extensions.ExecutableCommandline;
+import org.apache.maven.surefire.extensions.ForkChannel;
-import java.util.List;
+import javax.annotation.Nonnull;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+final class LegacyForkChannel implements ForkChannel
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ @Override
+ public String getForkNodeConnectionString()
+ {
+ return "pipe://";
+ }
+
+ @Nonnull
+ @Override
+ public ExecutableCommandline createExecutableCommandline() throws IOException
+ {
+ return new PipeProcessExecutor();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkNodeFactory.java
similarity index 65%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkNodeFactory.java
index cefeb33..7231d00 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkNodeFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.testset.DirectoryScannerParameters;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
/**
- * @author Kristian Rosenvold
+ *
*/
-interface DirectoryScannerParametersAware
+public class LegacyForkNodeFactory implements ForkNodeFactory
{
- void setDirectoryScannerParameters( DirectoryScannerParameters directoryScanner );
+ @Nonnull
+ @Override
+ public ForkChannel createForkChannel() throws IOException
+ {
+ return new LegacyForkChannel();
+ }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/NetworkingProcessExecutor.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/NetworkingProcessExecutor.java
new file mode 100644
index 0000000..71b75cc
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/NetworkingProcessExecutor.java
@@ -0,0 +1,218 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ExecutableCommandline;
+import org.apache.maven.surefire.extensions.StdErrStreamLine;
+import org.apache.maven.surefire.extensions.StdOutStreamLine;
+import org.apache.maven.surefire.shared.utils.cli.CommandLineUtils;
+import org.apache.maven.surefire.shared.utils.cli.Commandline;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.channels.CompletionHandler;
+import java.util.Scanner;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+import static java.nio.ByteBuffer.wrap;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/**
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+final class NetworkingProcessExecutor implements ExecutableCommandline
+{
+ private final AsynchronousServerSocketChannel server;
+ private final ExecutorService executorService;
+
+ NetworkingProcessExecutor( AsynchronousServerSocketChannel server, ExecutorService executorService )
+ {
+ this.server = server;
+ this.executorService = executorService;
+ }
+
+ @Nonnull
+ @Override
+ public <T> Callable<Integer> executeCommandLineAsCallable( @Nonnull T cli,
+ @Nonnull final CommandReader commands,
+ @Nonnull final EventHandler events,
+ StdOutStreamLine stdOut,
+ StdErrStreamLine stdErr,
+ @Nonnull Runnable runAfterProcessTermination )
+ throws Exception
+ {
+ server.accept( null, new CompletionHandler<AsynchronousSocketChannel, Object>()
+ {
+ @Override
+ public void completed( final AsynchronousSocketChannel client, Object attachment )
+ {
+ executorService.submit( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ InputStream is = toInputStream( client );
+ try
+ {
+ for ( Scanner scanner = new Scanner( is, "ASCII" ); scanner.hasNextLine(); )
+ {
+ if ( scanner.ioException() != null )
+ {
+ break;
+ }
+ events.handleEvent( scanner.nextLine() );
+ }
+ }
+ catch ( IllegalStateException e )
+ {
+ // scanner and InputStream is closed
+ try
+ {
+ client.close();
+ }
+ catch ( IOException ex )
+ {
+ // couldn't close the client channel
+ }
+ }
+ }
+ } );
+
+ executorService.submit( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ for ( Command cmd; !commands.isClosed(); )
+ {
+ cmd = commands.readNextCommand();
+ if ( cmd == null )
+ {
+ break;
+ }
+ MasterProcessCommand cmdType = cmd.getCommandType();
+ byte[] b = cmdType.hasDataType() ? cmdType.encode( cmd.getData() ) : cmdType.encode();
+ ByteBuffer bb = wrap( b );
+ do
+ {
+ client.write( bb ).get();
+ }
+ while ( bb.hasRemaining() );
+ }
+ }
+ catch ( Exception e )
+ {
+ // finished stream or error
+ try
+ {
+ client.close();
+ }
+ catch ( IOException ex )
+ {
+ // couldn't close the client channel
+ }
+ }
+ }
+ } );
+ }
+
+ @Override
+ public void failed( Throwable exc, Object attachment )
+ {
+ // write to dump file
+ // close the server
+ }
+ } );
+
+ return CommandLineUtils.executeCommandLineAsCallable( (Commandline) cli, null,
+ new StdOutAdapter( stdOut ), new StdErrAdapter( stdErr ), 0, runAfterProcessTermination, US_ASCII );
+ }
+
+ private static InputStream toInputStream( final AsynchronousSocketChannel client )
+ {
+ return new InputStream()
+ {
+ private final ByteBuffer bb = ByteBuffer.allocate( 64 * 1024 );
+ private boolean closed;
+
+ @Override
+ public int read() throws IOException
+ {
+ if ( closed )
+ {
+ return -1;
+ }
+
+ try
+ {
+ if ( !bb.hasRemaining() )
+ {
+ bb.clear();
+ if ( client.read( bb ).get() == 0 )
+ {
+ closed = true;
+ return -1;
+ }
+ bb.flip();
+ }
+ return bb.get();
+ }
+ catch ( InterruptedException e )
+ {
+ closed = true;
+ return -1;
+ }
+ catch ( ExecutionException e )
+ {
+ closed = true;
+ Throwable cause = e.getCause();
+ if ( cause instanceof IOException )
+ {
+ throw (IOException) cause;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ closed = true;
+ super.close();
+ }
+ };
+ }
+}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/PipeProcessExecutor.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/PipeProcessExecutor.java
new file mode 100644
index 0000000..f6e942b
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/PipeProcessExecutor.java
@@ -0,0 +1,144 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ExecutableCommandline;
+import org.apache.maven.surefire.extensions.StdErrStreamLine;
+import org.apache.maven.surefire.extensions.StdOutStreamLine;
+import org.apache.maven.surefire.shared.utils.cli.CommandLineUtils;
+import org.apache.maven.surefire.shared.utils.cli.Commandline;
+import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.Callable;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/**
+ * Commands which are sent from plugin to the forked jvm.
+ * <br>
+ * Events are received from the forked jvm.
+ * <br>
+ * <br>
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ * or data encoded with Base64
+ * <br>
+ * magic number : opcode [: Base64(opcode specific data)]*
+ *
+ * The command and event must be finished by the character ':' and New Line.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+final class PipeProcessExecutor
+ implements ExecutableCommandline
+{
+ @Override
+ @Nonnull
+ public <T> Callable<Integer> executeCommandLineAsCallable( @Nonnull T cli,
+ @Nonnull CommandReader commands,
+ @Nonnull EventHandler events,
+ StdOutStreamLine stdOut,
+ StdErrStreamLine stdErr,
+ @Nonnull Runnable runAfterProcessTermination )
+ throws Exception
+ {
+ return CommandLineUtils.executeCommandLineAsCallable( (Commandline) cli, new CommandReaderAdapter( commands ),
+ new EventHandlerAdapter( events ), new StdErrAdapter( stdErr ),
+ 0, runAfterProcessTermination, US_ASCII );
+ }
+
+ private static class EventHandlerAdapter implements StreamConsumer
+ {
+ private final EventHandler events;
+
+ private EventHandlerAdapter( EventHandler events )
+ {
+ this.events = events;
+ }
+
+ @Override
+ public void consumeLine( String line )
+ {
+ events.handleEvent( line );
+ }
+ }
+
+ private static class CommandReaderAdapter extends InputStream
+ {
+ private final CommandReader commands;
+ private byte[] currentBuffer;
+ private int currentPos;
+ private volatile boolean closed;
+
+ CommandReaderAdapter( CommandReader commands )
+ {
+ this.commands = commands;
+ }
+
+ @Override
+ public int read() throws IOException
+ {
+ if ( commands.isClosed() )
+ {
+ close();
+ }
+
+ if ( closed )
+ {
+ return -1;
+ }
+
+ if ( currentBuffer == null )
+ {
+ Command cmd = commands.readNextCommand();
+ if ( cmd == null )
+ {
+ currentPos = 0;
+ return -1;
+ }
+ MasterProcessCommand cmdType = cmd.getCommandType();
+ currentBuffer = cmdType.hasDataType() ? cmdType.encode( cmd.getData() ) : cmdType.encode();
+ }
+
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ int b = currentBuffer[currentPos++] & 0xff;
+ if ( currentPos == currentBuffer.length )
+ {
+ currentBuffer = null;
+ currentPos = 0;
+ }
+ return b;
+ }
+
+ @Override
+ public void close()
+ {
+ closed = true;
+ }
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdErrAdapter.java
similarity index 63%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdErrAdapter.java
index eddebed..52d352a 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdErrAdapter.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,24 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.surefire.extensions.StdErrStreamLine;
+import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+final class StdErrAdapter implements StreamConsumer
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final StdErrStreamLine stdErr;
+
+ StdErrAdapter( StdErrStreamLine stdErr )
+ {
+ this.stdErr = stdErr;
+ }
+
+ @Override
+ public void consumeLine( String line )
+ {
+ stdErr.handleLine( line );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdOutAdapter.java
similarity index 63%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdOutAdapter.java
index eddebed..4ca8cf5 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StdOutAdapter.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,24 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.surefire.extensions.StdOutStreamLine;
+import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+final class StdOutAdapter implements StreamConsumer
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final StdOutStreamLine stdOut;
+
+ StdOutAdapter( StdOutStreamLine stdOut )
+ {
+ this.stdOut = stdOut;
+ }
+
+ @Override
+ public void consumeLine( String line )
+ {
+ stdOut.handleLine( line );
+ }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
new file mode 100644
index 0000000..fb8f789
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
@@ -0,0 +1,84 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.extensions.ExecutableCommandline;
+import org.apache.maven.surefire.extensions.ForkChannel;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.net.StandardSocketOptions.SO_KEEPALIVE;
+import static java.net.StandardSocketOptions.SO_REUSEADDR;
+import static java.net.StandardSocketOptions.TCP_NODELAY;
+import static java.nio.channels.AsynchronousChannelGroup.withThreadPool;
+import static java.nio.channels.AsynchronousServerSocketChannel.open;
+import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
+
+/**
+ *
+ */
+final class SurefireForkChannel implements ForkChannel
+{
+ private final ExecutorService executorService;
+ private final AsynchronousServerSocketChannel server;
+ private final int serverPort;
+
+ SurefireForkChannel() throws IOException
+ {
+ executorService = Executors.newCachedThreadPool( newDaemonThreadFactory() );
+ server = open( withThreadPool( executorService ) );
+ server.setOption( SO_REUSEADDR, true );
+ server.setOption( TCP_NODELAY, true );
+ server.setOption( SO_KEEPALIVE, true );
+ server.bind( new InetSocketAddress( 0 ) );
+ serverPort = ( (InetSocketAddress) server.getLocalAddress() ).getPort();
+ }
+
+ @Override
+ public String getForkNodeConnectionString()
+ {
+ return "tcp://127.0.0.1:" + serverPort;
+ }
+
+ @Nonnull
+ @Override
+ public ExecutableCommandline createExecutableCommandline()
+ {
+ return new NetworkingProcessExecutor( server, executorService );
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ try
+ {
+ server.close();
+ }
+ finally
+ {
+ executorService.shutdownNow();
+ }
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkNodeFactory.java
similarity index 65%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkNodeFactory.java
index eddebed..c483619 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkNodeFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
-import java.util.List;
+import javax.annotation.Nonnull;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+public class SurefireForkNodeFactory implements ForkNodeFactory
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ @Nonnull
+ @Override
+ public ForkChannel createForkChannel() throws IOException
+ {
+ return new SurefireForkChannel();
+ }
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
index 9faa4eb..bc722e3 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
@@ -28,6 +28,7 @@ import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.util.DefaultScanResult;
import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
index b1e7c1e..e70b951 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
@@ -42,6 +42,7 @@ import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.suite.RunResult;
import org.codehaus.plexus.logging.Logger;
import org.junit.Before;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/CommonReflectorTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/CommonReflectorTest.java
index 1f94a75..4f954d4 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/CommonReflectorTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/CommonReflectorTest.java
@@ -23,15 +23,30 @@ import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
+import org.apache.maven.plugin.surefire.log.api.PrintStreamLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
+import org.hamcrest.MatcherAssert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import java.io.File;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
+import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
import static org.fest.assertions.Assertions.assertThat;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static org.powermock.reflect.Whitebox.getInternalState;
/**
@@ -96,4 +111,39 @@ public class CommonReflectorTest
assertThat( reportConfiguration.getConsoleOutputReporter().toString() )
.isEqualTo( consoleOutputReporter.toString() );
}
+
+ @Test
+ public void shouldProxyConsoleLogger()
+ {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ ConsoleLogger logger = spy( new PrintStreamLogger( System.out ) );
+ Object mirror = CommonReflector.createConsoleLogger( logger, cl );
+ MatcherAssert.assertThat( mirror, is( notNullValue() ) );
+ MatcherAssert.assertThat( mirror.getClass().getInterfaces()[0].getName(), is( ConsoleLogger.class.getName() ) );
+ MatcherAssert.assertThat( mirror, is( not( sameInstance( (Object) logger ) ) ) );
+ MatcherAssert.assertThat( mirror, is( instanceOf( ConsoleLoggerDecorator.class ) ) );
+ invokeMethodWithArray( mirror, getMethod( mirror, "info", String.class ), "Hi There!" );
+ verify( logger, times( 1 ) ).info( "Hi There!" );
+ }
+
+ @Test
+ public void testCreateConsoleLogger()
+ {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ ConsoleLogger consoleLogger = mock( ConsoleLogger.class );
+ ConsoleLogger decorator = (ConsoleLogger) CommonReflector.createConsoleLogger( consoleLogger, cl );
+ assertThat( decorator )
+ .isNotSameAs( consoleLogger );
+
+ assertThat( decorator.isDebugEnabled() ).isFalse();
+ when( consoleLogger.isDebugEnabled() ).thenReturn( true );
+ assertThat( decorator.isDebugEnabled() ).isTrue();
+ verify( consoleLogger, times( 2 ) ).isDebugEnabled();
+
+ decorator.info( "msg" );
+ ArgumentCaptor<String> argumentMsg = ArgumentCaptor.forClass( String.class );
+ verify( consoleLogger, times( 1 ) ).info( argumentMsg.capture() );
+ assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+ assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "msg" );
+ }
}
\ No newline at end of file
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
index ccf63f7..835ce8e 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
@@ -28,6 +28,7 @@ import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.util.DefaultScanResult;
import org.apache.maven.toolchain.Toolchain;
@@ -751,6 +752,12 @@ public class MojoMocklessTest
}
@Override
+ protected ForkNodeFactory getForkNode()
+ {
+ return null;
+ }
+
+ @Override
protected String getEnableProcessChecker()
{
return null;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireReflectorTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireReflectorTest.java
deleted file mode 100644
index 2553617..0000000
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireReflectorTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-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 org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
-import org.apache.maven.plugin.surefire.log.api.PrintStreamLogger;
-import org.apache.maven.surefire.booter.IsolatedClassLoader;
-import org.apache.maven.surefire.booter.SurefireReflector;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
-import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @see ConsoleLogger
- * @see SurefireReflector
- * @since 2.20
- */
-public class SurefireReflectorTest
-{
- private ConsoleLogger logger;
- private ClassLoader cl;
-
- @Before
- public void prepareData()
- {
- logger = spy( new PrintStreamLogger( System.out ) );
- cl = new IsolatedClassLoader( Thread.currentThread().getContextClassLoader(), false, "role" );
- }
-
- @Test
- public void shouldProxyConsoleLogger()
- {
- Object mirror = SurefireReflector.createConsoleLogger( logger, cl );
- assertThat( mirror, is( notNullValue() ) );
- assertThat( mirror.getClass().getInterfaces()[0].getName(), is( ConsoleLogger.class.getName() ) );
- assertThat( mirror, is( not( sameInstance( (Object) logger ) ) ) );
- assertThat( mirror, is( instanceOf( ConsoleLoggerDecorator.class ) ) );
- invokeMethodWithArray( mirror, getMethod( mirror, "info", String.class ), "Hi There!" );
- verify( logger, times( 1 ) ).info( "Hi There!" );
- }
-}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
index ca42c44..caf1376 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
@@ -260,9 +260,10 @@ public class BooterDeserializerProviderConfigurationTest
test = "aTest";
}
final File propsTest = booterSerializer.serialize( props, booterConfiguration, testProviderConfiguration, test,
- readTestsFromInStream, 51L, 1 );
+ readTestsFromInStream, 51L, 1, "pipe://" );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
assertEquals( "51", (Object) booterDeserializer.getPluginPid() );
+ assertEquals( "pipe://", booterDeserializer.getForkNodeConnectionString() );
return booterDeserializer.deserialize();
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
index 4e9bbc9..5054e6c 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -178,9 +178,10 @@ public class BooterDeserializerStartupConfigurationTest
BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
String aTest = "aTest";
File propsTest = booterSerializer.serialize( props, getProviderConfiguration(), startupConfiguration, aTest,
- false, null, 1 );
+ false, null, 1, null );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
assertNull( booterDeserializer.getPluginPid() );
+ assertNull( booterDeserializer.getForkNodeConnectionString() );
return booterDeserializer.getStartupConfiguration();
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
index 06fe754..f0d3482 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
@@ -27,7 +27,7 @@ import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
import org.apache.maven.surefire.booter.ForkedBooter;
import org.apache.maven.surefire.booter.StartupConfiguration;
-import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -80,6 +80,7 @@ public class DefaultForkConfigurationTest
private boolean reuseForks;
private Platform pluginPlatform;
private ConsoleLogger log;
+ private ForkNodeFactory forkNodeFactory;
@Before
public void setup()
@@ -97,6 +98,7 @@ public class DefaultForkConfigurationTest
reuseForks = true;
pluginPlatform = new Platform();
log = mock( ConsoleLogger.class );
+ forkNodeFactory = mock( ForkNodeFactory.class );
}
@Test
@@ -104,16 +106,15 @@ public class DefaultForkConfigurationTest
{
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -130,16 +131,15 @@ public class DefaultForkConfigurationTest
argLine = "";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -156,16 +156,15 @@ public class DefaultForkConfigurationTest
argLine = "\n\r";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -182,16 +181,15 @@ public class DefaultForkConfigurationTest
argLine = "-Dfile.encoding=UTF-8";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -209,16 +207,15 @@ public class DefaultForkConfigurationTest
argLine = "-Dfile.encoding=@{encoding}";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -235,16 +232,15 @@ public class DefaultForkConfigurationTest
argLine = "a\n\rb";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -261,16 +257,15 @@ public class DefaultForkConfigurationTest
argLine = "-Dthread=${surefire.threadNumber}";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
@@ -287,16 +282,15 @@ public class DefaultForkConfigurationTest
argLine = "-Dthread=${surefire.forkNumber}";
DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables,
- debug, forkCount, reuseForks, pluginPlatform, log )
+ debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory )
{
@Override
protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
@Nonnull String booterThatHasMainMethod,
@Nonnull StartupConfiguration config,
- @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
+ @Nonnull File dumpLogDirectory )
{
-
}
};
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
index 72e5372..16564a3 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -30,6 +30,7 @@ import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -44,9 +45,8 @@ import static java.util.Collections.singletonList;
import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
import static org.apache.maven.surefire.booter.ProcessCheckerType.ALL;
import static org.fest.util.Files.temporaryFolder;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
/**
*
@@ -225,7 +225,7 @@ public class ForkConfigurationTest
return new JarManifestForkConfiguration( emptyClasspath(), tmpDir, null,
cwd, new Properties(), argLine,
Collections.<String, String>emptyMap(), new String[0], false, 1, false,
- platform, new NullConsoleLogger() );
+ platform, new NullConsoleLogger(), mock( ForkNodeFactory.class ) );
}
// based on http://stackoverflow.com/questions/2591083/getting-version-of-java-in-runtime
@@ -233,6 +233,6 @@ public class ForkConfigurationTest
private static boolean isJavaVersionAtLeast7u60()
{
String[] javaVersionElements = System.getProperty( "java.runtime.version" ).split( "\\.|_|-b" );
- return Integer.valueOf( javaVersionElements[1] ) >= 7 && Integer.valueOf( javaVersionElements[3] ) >= 60;
+ return Integer.parseInt( javaVersionElements[1] ) >= 7 && Integer.parseInt( javaVersionElements[3] ) >= 60;
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
index 492c5c0..77cc49d 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfigurationTest.java
@@ -66,7 +66,7 @@ public class ModularClasspathForkConfigurationTest
ModularClasspathForkConfiguration config = new ModularClasspathForkConfiguration( booter, tmp, "", pwd,
new Properties(), "",
Collections.<String, String>emptyMap(), new String[0], true, 1, true,
- new Platform(), new NullConsoleLogger() );
+ new Platform(), new NullConsoleLogger(), null );
File patchFile = new File( "target" + separatorChar + "test-classes" );
File descriptor = new File( tmp, "module-info.class" );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
index bbc85d4..39789ac 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
@@ -21,12 +21,14 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import java.io.DataInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Iterator;
import java.util.NoSuchElementException;
@@ -34,7 +36,6 @@ import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.Tes
import static org.apache.maven.surefire.booter.Command.NOOP;
import static org.apache.maven.surefire.booter.Command.SKIP_SINCE_NEXT_TEST;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
import static org.apache.maven.surefire.booter.Shutdown.EXIT;
import static org.apache.maven.surefire.booter.Shutdown.KILL;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -137,15 +138,43 @@ public class TestLessInputStreamBuilderTest
throws IOException
{
TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
- TestLessInputStream pluginIs = builder.build();
+ final TestLessInputStream pluginIs = builder.build();
+ InputStream is = new InputStream()
+ {
+ private byte[] buffer;
+ private int idx;
+
+ @Override
+ public int read() throws IOException
+ {
+ if ( buffer == null )
+ {
+ idx = 0;
+ Command cmd = pluginIs.readNextCommand();
+ buffer = cmd == null ? null : cmd.getCommandType().encode();
+ }
+
+ if ( buffer != null )
+ {
+ byte b = buffer[idx++];
+ if ( idx == buffer.length )
+ {
+ buffer = null;
+ idx = 0;
+ }
+ return b;
+ }
+ throw new IOException();
+ }
+ };
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
builder.getImmediateCommands().shutdown( KILL );
builder.getImmediateCommands().noop();
- DataInputStream is = new DataInputStream( pluginIs );
- Command bye = decode( is );
+ Command bye = decoder.decode();
assertThat( bye, is( notNullValue() ) );
assertThat( bye.getCommandType(), is( SHUTDOWN ) );
assertThat( bye.getData(), is( KILL.name() ) );
- Command noop = decode( is );
+ Command noop = decoder.decode();
assertThat( noop, is( notNullValue() ) );
assertThat( noop.getCommandType(), is( MasterProcessCommand.NOOP ) );
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
index 21bc663..f863be1 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
@@ -20,11 +20,13 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.junit.Test;
-import java.io.DataInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Thread.State;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Callable;
@@ -32,11 +34,13 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
+import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertTrue;
/**
* Asserts that this stream properly reads bytes from queue.
@@ -47,13 +51,13 @@ import static org.hamcrest.Matchers.notNullValue;
public class TestProvidingInputStreamTest
{
@Test
- public void closedStreamShouldReturnEndOfStream()
+ public void closedStreamShouldReturnNullAsEndOfStream()
throws IOException
{
Queue<String> commands = new ArrayDeque<>();
TestProvidingInputStream is = new TestProvidingInputStream( commands );
is.close();
- assertThat( is.read(), is( -1 ) );
+ assertThat( is.readNextCommand(), is( nullValue() ) );
}
@Test
@@ -63,22 +67,22 @@ public class TestProvidingInputStreamTest
Queue<String> commands = new ArrayDeque<>();
final TestProvidingInputStream is = new TestProvidingInputStream( commands );
final Thread streamThread = Thread.currentThread();
- FutureTask<Thread.State> futureTask = new FutureTask<>( new Callable<Thread.State>()
+ FutureTask<State> futureTask = new FutureTask<>( new Callable<State>()
{
@Override
- public Thread.State call()
+ public State call()
{
- sleep( 1000 );
- Thread.State state = streamThread.getState();
+ sleep( 1000L );
+ State state = streamThread.getState();
is.close();
return state;
}
} );
Thread assertionThread = new Thread( futureTask );
assertionThread.start();
- assertThat( is.read(), is( -1 ) );
- Thread.State state = futureTask.get();
- assertThat( state, is( Thread.State.WAITING ) );
+ assertThat( is.readNextCommand(), is( nullValue() ) );
+ State state = futureTask.get();
+ assertThat( state, is( State.WAITING ) );
}
@Test
@@ -96,16 +100,22 @@ public class TestProvidingInputStreamTest
is.provideNewTest();
}
} ).start();
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 1 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
+
+ StringBuilder stream = new StringBuilder();
+ for ( int i = 0; i < 82; i++ )
+ {
+ Command cmd = is.readNextCommand();
+ assertThat( cmd.getData(), is( nullValue() ) );
+ stream.append( new String( cmd.getCommandType().encode(), US_ASCII ) );
+ }
+ assertThat( stream.toString(),
+ is( ":maven-surefire-std-out:testset-finished::maven-surefire-std-out:testset-finished:" ) );
+
+ boolean emptyStream = isInputStreamEmpty( is );
+
is.close();
- assertThat( is.read(), is( -1 ) );
+ assertTrue( emptyStream );
+ assertThat( is.readNextCommand(), is( nullValue() ) );
}
@Test
@@ -123,34 +133,62 @@ public class TestProvidingInputStreamTest
is.provideNewTest();
}
} ).start();
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 0 ) );
- assertThat( is.read(), is( 4 ) );
- assertThat( is.read(), is( (int) 'T' ) );
- assertThat( is.read(), is( (int) 'e' ) );
- assertThat( is.read(), is( (int) 's' ) );
- assertThat( is.read(), is( (int) 't' ) );
+
+ StringBuilder stream = new StringBuilder();
+ for ( int i = 0; i < 43; i++ )
+ {
+ Command cmd = is.readNextCommand();
+ assertThat( cmd.getData(), is( nullValue() ) );
+ stream.append( new String( is.readNextCommand().getCommandType().encode(), US_ASCII ) );
+ }
+ assertThat( stream.toString(),
+ is( ":maven-surefire-std-out:run-testclass:Test:" ) );
+
+ is.close();
}
@Test
public void shouldDecodeTwoCommands()
throws IOException
{
- TestProvidingInputStream pluginIs = new TestProvidingInputStream( new ConcurrentLinkedQueue<String>() );
+ final TestProvidingInputStream pluginIs = new TestProvidingInputStream( new ConcurrentLinkedQueue<String>() );
+ InputStream is = new InputStream()
+ {
+ private byte[] buffer;
+ private int idx;
+
+ @Override
+ public int read() throws IOException
+ {
+ if ( buffer == null )
+ {
+ idx = 0;
+ Command cmd = pluginIs.readNextCommand();
+ buffer = cmd == null ? null : cmd.getCommandType().encode();
+ }
+
+ if ( buffer != null )
+ {
+ byte b = buffer[idx++];
+ if ( idx == buffer.length )
+ {
+ buffer = null;
+ idx = 0;
+ }
+ return b;
+ }
+ throw new IOException();
+ }
+ };
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
pluginIs.acknowledgeByeEventReceived();
pluginIs.noop();
- DataInputStream is = new DataInputStream( pluginIs );
- Command bye = decode( is );
+ Command bye = decoder.decode();
assertThat( bye, is( notNullValue() ) );
assertThat( bye.getCommandType(), is( BYE_ACK ) );
- Command noop = decode( is );
+ Command noop = decoder.decode();
assertThat( noop, is( notNullValue() ) );
- assertThat( noop.getCommandType(), is( MasterProcessCommand.NOOP ) );
+ assertThat( noop.getCommandType(), is( NOOP ) );
}
private static void sleep( long millis )
@@ -164,4 +202,40 @@ public class TestProvidingInputStreamTest
// do nothing
}
}
+
+ /**
+ * Waiting (max of 20 seconds)
+ * @param is examined stream
+ * @return {@code true} if the {@link InputStream#read()} is waiting for a new byte.
+ */
+ private static boolean isInputStreamEmpty( final TestProvidingInputStream is )
+ {
+ Thread t = new Thread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ is.readNextCommand();
+ }
+ catch ( IOException e )
+ {
+ Throwable cause = e.getCause();
+ Throwable err = cause == null ? e : cause;
+ System.err.println( err.toString() );
+ }
+ }
+ } );
+ t.start();
+ State state;
+ int loops = 0;
+ do
+ {
+ sleep( 100L );
+ state = t.getState();
+ } while ( state == State.NEW && loops++ < 200 );
+ t.interrupt();
+ return state == State.WAITING || state == State.TIMED_WAITING;
+ }
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index b1e3b22..21cee75 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -28,7 +28,6 @@ import org.apache.maven.plugin.surefire.AbstractSurefireMojoTest;
import org.apache.maven.plugin.surefire.CommonReflectorTest;
import org.apache.maven.plugin.surefire.MojoMocklessTest;
import org.apache.maven.plugin.surefire.SurefireHelperTest;
-import org.apache.maven.plugin.surefire.SurefireReflectorTest;
import org.apache.maven.plugin.surefire.SurefirePropertiesTest;
import org.apache.maven.plugin.surefire.booterclient.BooterDeserializerProviderConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.BooterDeserializerStartupConfigurationTest;
@@ -89,7 +88,6 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( TestProvidingInputStreamTest.class ) );
suite.addTest( new JUnit4TestAdapter( TestLessInputStreamBuilderTest.class ) );
suite.addTest( new JUnit4TestAdapter( SPITest.class ) );
- suite.addTest( new JUnit4TestAdapter( SurefireReflectorTest.class ) );
suite.addTest( new JUnit4TestAdapter( SurefireHelperTest.class ) );
suite.addTest( new JUnit4TestAdapter( AbstractSurefireMojoTest.class ) );
suite.addTest( new JUnit4TestAdapter( DefaultForkConfigurationTest.class ) );
diff --git a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
index b39181a..5f6edea 100644
--- a/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
+++ b/maven-surefire-plugin/src/main/java/org/apache/maven/plugin/surefire/SurefirePlugin.java
@@ -29,6 +29,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.suite.RunResult;
import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
@@ -365,6 +366,9 @@ public class SurefirePlugin
@Parameter( property = "surefire.useModulePath", defaultValue = "true" )
private boolean useModulePath;
+ @Parameter( property = "surefire.forkNode" )
+ private ForkNodeFactory forkNode;
+
/**
* You can selectively exclude individual environment variables by enumerating their keys.
* <br>
@@ -831,4 +835,10 @@ public class SurefirePlugin
{
return enableProcessChecker;
}
+
+ @Override
+ protected final ForkNodeFactory getForkNode()
+ {
+ return forkNode;
+ }
}
diff --git a/pom.xml b/pom.xml
index 1bcb356..49f0b14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
<module>surefire-logger-api</module>
<module>surefire-api</module>
<module>surefire-extensions-api</module>
+ <module>surefire-extensions-spi</module>
<module>surefire-booter</module>
<module>surefire-grouper</module>
<module>surefire-providers</module>
@@ -474,10 +475,8 @@
</goals>
<configuration>
<includes>
- <include>org/apache/maven/shared/utils/logging/*.java</include>
<include>HelpMojo.java</include>
<include>**/HelpMojo.java</include>
- <include>org/apache/maven/plugin/failsafe/xmlsummary/*.java</include>
</includes>
<compilerArgs>
<!-- FIXME: maven-plugin-plugin therefore used -syntax or none due to HelpMojo -->
@@ -493,14 +492,13 @@
</goals>
<configuration>
<excludes>
- <exclude>org/apache/maven/shared/utils/logging/*.java</exclude>
<exclude>HelpMojo.java</exclude>
<exclude>**/HelpMojo.java</exclude>
- <exclude>org/apache/maven/plugin/failsafe/xmlsummary/*.java</exclude>
</excludes>
<compilerArgs>
<arg>-Xdoclint:all</arg>
</compilerArgs>
+ <verbose>true</verbose>
</configuration>
</execution>
</executions>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
index ec05580..9d2dc73 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
@@ -20,6 +20,7 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.DefaultDirectConsoleReporter;
@@ -46,14 +47,12 @@ import static java.util.Collections.emptyList;
* @author Kristian Rosenvold
*/
public class BaseProviderFactory
- implements DirectoryScannerParametersAware, ReporterConfigurationAware, SurefireClassLoadersAware, TestRequestAware,
- ProviderPropertiesAware, ProviderParameters, TestArtifactInfoAware, RunOrderParametersAware, MainCliOptionsAware,
- FailFastAware, ShutdownAware
+ implements ProviderParameters
{
- private final ReporterFactory reporterFactory;
-
private final boolean insideFork;
+ private ReporterFactory reporterFactory;
+
private ForkedChannelEncoder forkedChannelEncoder;
private List<CommandLineOption> mainCliOptions = emptyList();
@@ -74,17 +73,27 @@ public class BaseProviderFactory
private int skipAfterFailureCount;
- private Shutdown shutdown;
-
private Integer systemExitTimeout;
- public BaseProviderFactory( ReporterFactory reporterFactory, boolean insideFork )
+ private CommandChainReader commandReader;
+
+ public BaseProviderFactory( boolean insideFork )
{
- this.reporterFactory = reporterFactory;
this.insideFork = insideFork;
}
@Override
+ public CommandChainReader getCommandReader()
+ {
+ return commandReader;
+ }
+
+ public void setCommandReader( CommandChainReader commandReader )
+ {
+ this.commandReader = commandReader;
+ }
+
+ @Override
@Deprecated
public DirectoryScanner getDirectoryScanner()
{
@@ -114,25 +123,27 @@ public class BaseProviderFactory
? null : new DefaultRunOrderCalculator( runOrderParameters, getThreadCount() );
}
+ public void setReporterFactory( ReporterFactory reporterFactory )
+ {
+ this.reporterFactory = reporterFactory;
+ }
+
@Override
public ReporterFactory getReporterFactory()
{
return reporterFactory;
}
- @Override
public void setDirectoryScannerParameters( DirectoryScannerParameters directoryScannerParameters )
{
this.directoryScannerParameters = directoryScannerParameters;
}
- @Override
public void setReporterConfiguration( ReporterConfiguration reporterConfiguration )
{
this.reporterConfiguration = reporterConfiguration;
}
- @Override
public void setClassLoaders( ClassLoader testClassLoader )
{
this.testClassLoader = testClassLoader;
@@ -145,7 +156,6 @@ public class BaseProviderFactory
: new DefaultDirectConsoleReporter( reporterConfiguration.getOriginalSystemOut() );
}
- @Override
public void setTestRequest( TestRequest testRequest )
{
this.testRequest = testRequest;
@@ -175,7 +185,6 @@ public class BaseProviderFactory
return testClassLoader;
}
- @Override
public void setProviderProperties( Map<String, String> providerProperties )
{
this.providerProperties = providerProperties;
@@ -193,13 +202,11 @@ public class BaseProviderFactory
return testArtifactInfo;
}
- @Override
public void setTestArtifactInfo( TestArtifactInfo testArtifactInfo )
{
this.testArtifactInfo = testArtifactInfo;
}
- @Override
public void setRunOrderParameters( RunOrderParameters runOrderParameters )
{
this.runOrderParameters = runOrderParameters;
@@ -211,7 +218,11 @@ public class BaseProviderFactory
return mainCliOptions;
}
- @Override
+ /**
+ * CLI options in plugin (main) JVM process.
+ *
+ * @param mainCliOptions options
+ */
public void setMainCliOptions( List<CommandLineOption> mainCliOptions )
{
this.mainCliOptions = mainCliOptions == null ? Collections.<CommandLineOption>emptyList() : mainCliOptions;
@@ -223,7 +234,11 @@ public class BaseProviderFactory
return skipAfterFailureCount;
}
- @Override
+ /**
+ * See the plugin configuration parameter "skipAfterFailureCount".
+ *
+ * @param skipAfterFailureCount the value in config parameter "skipAfterFailureCount"
+ */
public void setSkipAfterFailureCount( int skipAfterFailureCount )
{
this.skipAfterFailureCount = skipAfterFailureCount;
@@ -236,18 +251,6 @@ public class BaseProviderFactory
}
@Override
- public Shutdown getShutdown()
- {
- return shutdown;
- }
-
- @Override
- public void setShutdown( Shutdown shutdown )
- {
- this.shutdown = shutdown;
- }
-
- @Override
public Integer getSystemExitTimeout()
{
return systemExitTimeout;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java
index f05c0f6..834317b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import java.util.Objects;
+
import static java.util.Objects.requireNonNull;
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
@@ -47,6 +49,11 @@ public final class Command
this.data = data;
}
+ public Command( MasterProcessCommand command )
+ {
+ this( command, null );
+ }
+
public static Command toShutdown( Shutdown shutdownType )
{
return new Command( SHUTDOWN, shutdownType.name() );
@@ -57,11 +64,6 @@ public final class Command
return new Command( RUN_CLASS, runClass );
}
- public Command( MasterProcessCommand command )
- {
- this( command, null );
- }
-
public MasterProcessCommand getCommandType()
{
return command;
@@ -78,18 +80,13 @@ public final class Command
*/
public Shutdown toShutdownData()
{
- if ( !isType( SHUTDOWN ) )
+ if ( command != SHUTDOWN )
{
throw new IllegalStateException( "expected MasterProcessCommand.SHUTDOWN" );
}
return isBlank( data ) ? DEFAULT : Shutdown.valueOf( data );
}
- public boolean isType( MasterProcessCommand command )
- {
- return command == this.command;
- }
-
@Override
public boolean equals( Object o )
{
@@ -105,7 +102,7 @@ public final class Command
Command arg = (Command) o;
- return command == arg.command && ( data == null ? arg.data == null : data.equals( arg.data ) );
+ return command == arg.command && Objects.equals( data, arg.data );
}
@Override
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
index eddebed..527782d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
@@ -19,17 +19,31 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
-
/**
- * CLI options in plugin (main) JVM process.
+ * magic number : opcode [: opcode specific data]*
+ * <br>
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public final class MasterProcessChannelEncoder
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+
+ private static final String MAGIC_NUMBER = ":maven:surefire:std:out:";
+
+ /**
+ * Encodes opcode and data.
+ *
+ * @param operation opcode
+ * @param data data
+ * @return encoded command
+ */
+ private static StringBuilder encode( String operation, String data )
+ {
+ StringBuilder s = new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( operation );
+
+ return data == null ? s : s.append( ':' ).append( data );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
index 7c4520f..182eddc 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
@@ -19,44 +19,49 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.DataInputStream;
-import java.io.IOException;
-
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.Objects.requireNonNull;
-import static java.lang.String.format;
/**
* Commands which are sent from plugin to the forked jvm.
* Support and methods related to the commands.
+ * <br>
+ * <br>
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ * or data encoded with Base64
+ * <br>
+ * magic number : opcode [: Base64(opcode specific data)]*
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
public enum MasterProcessCommand
{
- RUN_CLASS( 0, String.class ),
- TEST_SET_FINISHED( 1, Void.class ),
- SKIP_SINCE_NEXT_TEST( 2, Void.class ),
- SHUTDOWN( 3, String.class ),
+ RUN_CLASS( "run-testclass", String.class ),
+ TEST_SET_FINISHED( "testset-finished", Void.class ),
+ SKIP_SINCE_NEXT_TEST( "skip-since-next-test", Void.class ),
+ SHUTDOWN( "shutdown", String.class ),
/** To tell a forked process that the master process is still alive. Repeated after 10 seconds. */
- NOOP( 4, Void.class ),
- BYE_ACK( 5, Void.class );
+ NOOP( "noop", Void.class ),
+ BYE_ACK( "bye-ack", Void.class );
+
+ private static final String MAGIC_NUMBER = ":maven-surefire-std-out:";
- private final int id;
+ private final String opcodeName;
private final Class<?> dataType;
- MasterProcessCommand( int id, Class<?> dataType )
+ MasterProcessCommand( String opcodeName, Class<?> dataType )
{
- this.id = id;
+ this.opcodeName = opcodeName;
this.dataType = requireNonNull( dataType, "dataType cannot be null" );
}
- public int getId()
+ public String getOpcode()
{
- return id;
+ return opcodeName;
}
public Class<?> getDataType()
@@ -69,7 +74,18 @@ public enum MasterProcessCommand
return dataType != Void.class;
}
- @SuppressWarnings( "checkstyle:magicnumber" )
+ public static MasterProcessCommand byOpcode( String opcode )
+ {
+ for ( MasterProcessCommand cmd : values() )
+ {
+ if ( cmd.opcodeName.equals( opcode ) )
+ {
+ return cmd;
+ }
+ }
+ return null;
+ }
+
public byte[] encode( String data )
{
if ( !hasDataType() )
@@ -82,109 +98,42 @@ public enum MasterProcessCommand
throw new IllegalArgumentException( "Data type can be only " + String.class );
}
- final byte[] dataBytes = fromDataType( data );
- final int len = dataBytes.length;
-
- final byte[] encoded = new byte[8 + len];
-
- final int command = getId();
- setCommandAndDataLength( command, len, encoded );
- System.arraycopy( dataBytes, 0, encoded, 8, len );
-
- return encoded;
+ return encode( opcodeName, data )
+ .toString()
+ .getBytes( US_ASCII );
}
- @SuppressWarnings( "checkstyle:magicnumber" )
public byte[] encode()
{
if ( getDataType() != Void.class )
{
throw new IllegalArgumentException( "Data type can be only " + getDataType() );
}
- byte[] encoded = new byte[8];
- int command = getId();
- setCommandAndDataLength( command, 0, encoded );
- return encoded;
- }
-
- public static Command decode( DataInputStream is )
- throws IOException
- {
- MasterProcessCommand command = resolve( is.readInt() );
- if ( command == null )
- {
- return null;
- }
- else
- {
- int dataLength = is.readInt();
- if ( dataLength > 0 )
- {
- byte[] buffer = new byte[ dataLength ];
- is.readFully( buffer );
- if ( command.getDataType() == Void.class )
- {
- throw new IOException( format( "Command %s unexpectedly read Void data with length %d.",
- command, dataLength ) );
- }
-
- String data = command.toDataTypeAsString( buffer );
- return new Command( command, data );
- }
- else
- {
- return new Command( command );
- }
- }
+ return encode( opcodeName, null )
+ .toString()
+ .getBytes( US_ASCII );
}
- String toDataTypeAsString( byte... data )
+ /**
+ * Encodes opcode and data.
+ *
+ * @param operation opcode
+ * @param data data
+ * @return encoded command
+ */
+ private static StringBuilder encode( String operation, String data )
{
- switch ( this )
- {
- case RUN_CLASS:
- case SHUTDOWN:
- return new String( data, US_ASCII );
- default:
- return null;
- }
- }
+ StringBuilder s = new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( operation );
- byte[] fromDataType( String data )
- {
- switch ( this )
+ if ( data != null )
{
- case RUN_CLASS:
- case SHUTDOWN:
- return data.getBytes( US_ASCII );
- default:
- return new byte[0];
+ s.append( ':' )
+ .append( data );
}
- }
- static MasterProcessCommand resolve( int id )
- {
- for ( MasterProcessCommand command : values() )
- {
- if ( id == command.id )
- {
- return command;
- }
- }
- return null;
- }
-
- @SuppressWarnings( "checkstyle:magicnumber" )
- static void setCommandAndDataLength( int command, int dataLength, byte... encoded )
- {
- encoded[0] = (byte) ( command >>> 24 );
- encoded[1] = (byte) ( command >>> 16 );
- encoded[2] = (byte) ( command >>> 8 );
- encoded[3] = (byte) command;
- encoded[4] = (byte) ( dataLength >>> 24 );
- encoded[5] = (byte) ( dataLength >>> 16 );
- encoded[6] = (byte) ( dataLength >>> 8 );
- encoded[7] = (byte) dataLength;
+ return s.append( ':' );
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java
deleted file mode 100644
index 3bee07d..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.RunOrderParameters;
-
-/**
- * @author Kristian Rosenvold
- */
-interface RunOrderParametersAware
-{
- void setRunOrderParameters( RunOrderParameters runOrderParameters );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java
deleted file mode 100644
index 9898061..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.TestArtifactInfo;
-
-/**
- * @author Kristian Rosenvold
- */
-interface TestArtifactInfoAware
-{
- void setTestArtifactInfo( TestArtifactInfo testArtifactInfo );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java
deleted file mode 100644
index 3e98b92..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.TestRequest;
-
-/**
- * @author Kristian Rosenvold
- */
-interface TestRequestAware
-{
- void setTestRequest( TestRequest testSuiteDefinition );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
similarity index 62%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
index 8c65be3..2c94e9d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.providerapi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.report.ReporterConfiguration;
+import org.apache.maven.surefire.testset.TestSetFailedException;
/**
- * @author Kristian Rosenvold
+ * Hiding CommandReader instance in provider.
*/
-interface ReporterConfigurationAware
+public interface CommandChainReader
{
- void setReporterConfiguration( ReporterConfiguration reporterConfiguration );
+ boolean awaitStarted()
+ throws TestSetFailedException;
+
+ void addTestsFinishedListener( CommandListener listener );
+
+ void addSkipNextTestsListener( CommandListener listener );
+
+ void addShutdownListener( CommandListener listener );
+
+ void removeListener( CommandListener listener );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
similarity index 90%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
index 523ca76..b0d8870 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.providerapi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.booter.Command;
+
/**
* Command listener interface.
*/
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
new file mode 100644
index 0000000..6c64b25
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
@@ -0,0 +1,47 @@
+package org.apache.maven.surefire.providerapi;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.booter.Command;
+
+import java.io.IOException;
+
+/**
+ * An abstraction for physical decoder of commands. The commands are sent from master Maven process and
+ * received by the child forked Surefire process. The session must be open after the MasterProcessChannelDecoderFactory
+ * has created the decoder instance. The session can be closed on the decoder instance.
+ */
+public interface MasterProcessChannelDecoder
+ extends AutoCloseable
+{
+ /**
+ * Reads the bytes from a channel, waiting until the command is read completely or
+ * the channel throws {@link java.io.EOFException}.
+ * <br>
+ * This method is called in a single Thread. The constructor can be called within another thread.
+ *
+ * @return decoded command
+ * @throws IOException exception in channel
+ */
+ Command decode() throws IOException;
+
+ @Override
+ void close() throws IOException;
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
index 0fea537..e4caae7 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.providerapi;
*/
import org.apache.maven.surefire.booter.ForkedChannelEncoder;
-import org.apache.maven.surefire.booter.Shutdown;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReporterConfiguration;
@@ -147,9 +146,9 @@ public interface ProviderParameters
*/
boolean isInsideFork();
- Shutdown getShutdown();
-
Integer getSystemExitTimeout();
ForkedChannelEncoder getForkedChannelEncoder();
+
+ CommandChainReader getCommandReader();
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
index c7c123a..e7ed763 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
@@ -41,7 +41,7 @@ import static org.apache.maven.surefire.testset.ResolvedTest.Type.METHOD;
* composed of included and excluded tests.<br>
* The methods {@link #shouldRun(String, String)} are filters easily used in JUnit filter or TestNG.
* This class is independent of JUnit and TestNG API.<br>
- * It is accessed by Java Reflection API in {@link org.apache.maven.surefire.booter.SurefireReflector}
+ * It is accessed by Java Reflection API in {@code org.apache.maven.surefire.booter.SurefireReflector}
* using specific ClassLoader.
*/
public class TestListResolver
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
index 57e9ea7..2273842 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/ReflectionUtils.java
@@ -132,25 +132,6 @@ public final class ReflectionUtils
}
}
- public static Object instantiateTwoArgs( ClassLoader classLoader, String className, Class<?> param1Class,
- Object param1, Class param2Class, Object param2 )
- {
- try
- {
- Class<?> aClass = loadClass( classLoader, className );
- Constructor constructor = getConstructor( aClass, param1Class, param2Class );
- return constructor.newInstance( param1, param2 );
- }
- catch ( InvocationTargetException e )
- {
- throw new SurefireReflectionException( e.getTargetException() );
- }
- catch ( ReflectiveOperationException e )
- {
- throw new SurefireReflectionException( e );
- }
- }
-
public static void invokeSetter( Object o, String name, Class<?> value1clazz, Object value )
{
Method setter = getMethod( o, name, value1clazz );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DaemonThreadFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DaemonThreadFactory.java
index 3610a4b..06ddc53 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DaemonThreadFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DaemonThreadFactory.java
@@ -19,8 +19,8 @@ package org.apache.maven.surefire.util.internal;
* under the License.
*/
+import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates new daemon Thread.
@@ -28,29 +28,16 @@ import java.util.concurrent.atomic.AtomicInteger;
public final class DaemonThreadFactory
implements ThreadFactory
{
- private static final AtomicInteger POOL_NUMBER = new AtomicInteger( 1 );
-
- private final AtomicInteger threadNumber = new AtomicInteger( 1 );
-
- private final ThreadGroup group;
-
- private final String namePrefix;
+ private static final ThreadFactory DEFAULT_THREAD_FACTORY = Executors.defaultThreadFactory();
private DaemonThreadFactory()
{
- SecurityManager s = System.getSecurityManager();
- group = s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
- namePrefix = "pool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
}
@Override
public Thread newThread( Runnable r )
{
- Thread t = new Thread( group, r, namePrefix + threadNumber.getAndIncrement() );
- if ( t.getPriority() != Thread.NORM_PRIORITY )
- {
- t.setPriority( Thread.NORM_PRIORITY );
- }
+ Thread t = DEFAULT_THREAD_FACTORY.newThread( r );
t.setDaemon( true );
return t;
}
@@ -71,34 +58,19 @@ public final class DaemonThreadFactory
public static Thread newDaemonThread( Runnable r )
{
- SecurityManager s = System.getSecurityManager();
- ThreadGroup group = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
- Thread t = new Thread( group, r );
- if ( t.getPriority() != Thread.NORM_PRIORITY )
- {
- t.setPriority( Thread.NORM_PRIORITY );
- }
- t.setDaemon( true );
- return t;
+ return new DaemonThreadFactory().newThread( r );
}
public static Thread newDaemonThread( Runnable r, String name )
{
- SecurityManager s = System.getSecurityManager();
- ThreadGroup group = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
- Thread t = new Thread( group, r, name );
- if ( t.getPriority() != Thread.NORM_PRIORITY )
- {
- t.setPriority( Thread.NORM_PRIORITY );
- }
- t.setDaemon( true );
+ Thread t = new DaemonThreadFactory().newThread( r );
+ t.setName( name );
return t;
}
private static class NamedThreadFactory
implements ThreadFactory
{
-
private final String name;
private NamedThreadFactory( String name )
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index 38f0c48..ea27d8a 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -23,11 +23,8 @@ import junit.framework.JUnit4TestAdapter;
import junit.framework.Test;
import org.apache.maven.plugin.surefire.runorder.ThreadedExecutionSchedulerTest;
import org.apache.maven.surefire.SpecificTestClassFilterTest;
-import org.apache.maven.surefire.booter.CommandReaderTest;
import org.apache.maven.surefire.booter.ForkedChannelEncoderTest;
import org.apache.maven.surefire.booter.ForkingRunListenerTest;
-import org.apache.maven.surefire.booter.MasterProcessCommandTest;
-import org.apache.maven.surefire.booter.SurefireReflectorTest;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriterTest;
import org.apache.maven.surefire.suite.RunResultTest;
import org.apache.maven.surefire.testset.FundamentalFilterTest;
@@ -51,11 +48,8 @@ import org.junit.runners.Suite;
* @since 2.19
*/
@Suite.SuiteClasses( {
- CommandReaderTest.class,
ThreadedExecutionSchedulerTest.class,
ForkingRunListenerTest.class,
- MasterProcessCommandTest.class,
- SurefireReflectorTest.class,
LegacyPojoStackTraceWriterTest.class,
RunResultTest.class,
ResolvedTestTest.class,
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
deleted file mode 100644
index cfd4d5f..0000000
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import junit.framework.TestCase;
-import org.junit.Rule;
-import org.junit.rules.ExpectedException;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.resolve;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.setCommandAndDataLength;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
- */
-public class MasterProcessCommandTest
- extends TestCase
-{
- @Rule
- public final ExpectedException exception = ExpectedException.none();
-
- public void testEncodedStreamSequence()
- {
- byte[] streamSequence = new byte[10];
- streamSequence[8] = (byte) 'T';
- streamSequence[9] = (byte) 'e';
- setCommandAndDataLength( 256, 2, streamSequence );
- assertEquals( streamSequence[0], (byte) 0 );
- assertEquals( streamSequence[1], (byte) 0 );
- assertEquals( streamSequence[2], (byte) 1 );
- assertEquals( streamSequence[3], (byte) 0 );
- assertEquals( streamSequence[4], (byte) 0 );
- assertEquals( streamSequence[5], (byte) 0 );
- assertEquals( streamSequence[6], (byte) 0 );
- assertEquals( streamSequence[7], (byte) 2 );
- // remain unchanged
- assertEquals( streamSequence[8], (byte) 'T' );
- assertEquals( streamSequence[9], (byte) 'e' );
- }
-
- public void testResolved()
- {
- for ( MasterProcessCommand command : MasterProcessCommand.values() )
- {
- assertThat( command, is( resolve( command.getId() ) ) );
- }
- }
-
- public void testDataToByteArrayAndBack()
- {
- String dummyData = "pkg.Test";
- for ( MasterProcessCommand command : MasterProcessCommand.values() )
- {
- switch ( command )
- {
- case RUN_CLASS:
- assertEquals( String.class, command.getDataType() );
- byte[] encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 8 ) );
- assertThat( encoded[0], is( (byte) 'p' ) );
- assertThat( encoded[1], is( (byte) 'k' ) );
- assertThat( encoded[2], is( (byte) 'g' ) );
- assertThat( encoded[3], is( (byte) '.' ) );
- assertThat( encoded[4], is( (byte) 'T' ) );
- assertThat( encoded[5], is( (byte) 'e' ) );
- assertThat( encoded[6], is( (byte) 's' ) );
- assertThat( encoded[7], is( (byte) 't' ) );
- String decoded = command.toDataTypeAsString( encoded );
- assertThat( decoded, is( dummyData ) );
- break;
- case TEST_SET_FINISHED:
- case SKIP_SINCE_NEXT_TEST:
- case NOOP:
- case BYE_ACK:
- assertEquals( Void.class, command.getDataType() );
- encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 0 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertNull( decoded );
- break;
- case SHUTDOWN:
- assertEquals( String.class, command.getDataType() );
- encoded = command.fromDataType( Shutdown.EXIT.name() );
- assertThat( encoded.length, is( 4 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertThat( decoded, is( Shutdown.EXIT.name() ) );
- break;
- default:
- fail();
- }
- assertThat( command, is( resolve( command.getId() ) ) );
- }
- }
-
- public void testEncodedDecodedIsSameForRunClass()
- throws IOException
- {
- byte[] encoded = RUN_CLASS.encode( "pkg.Test" );
- assertThat( encoded.length, is( 16 ) );
- assertThat( encoded[0], is( (byte) 0 ) );
- assertThat( encoded[1], is( (byte) 0 ) );
- assertThat( encoded[2], is( (byte) 0 ) );
- assertThat( encoded[3], is( (byte) 0 ) );
- assertThat( encoded[4], is( (byte) 0 ) );
- assertThat( encoded[5], is( (byte) 0 ) );
- assertThat( encoded[6], is( (byte) 0 ) );
- assertThat( encoded[7], is( (byte) 8 ) );
- assertThat( encoded[8], is( (byte) 'p' ) );
- assertThat( encoded[9], is( (byte) 'k' ) );
- assertThat( encoded[10], is( (byte) 'g' ) );
- assertThat( encoded[11], is( (byte) '.' ) );
- assertThat( encoded[12], is( (byte) 'T' ) );
- assertThat( encoded[13], is( (byte) 'e' ) );
- assertThat( encoded[14], is( (byte) 's' ) );
- assertThat( encoded[15], is( (byte) 't' ) );
- Command command = decode( new DataInputStream( new ByteArrayInputStream( encoded ) ) );
- assertNotNull( command );
- assertThat( command.getCommandType(), is( RUN_CLASS ) );
- assertThat( command.getData(), is( "pkg.Test" ) );
- }
-
- public void testShouldDecodeTwoCommands() throws IOException
- {
- byte[] cmd1 = BYE_ACK.encode();
- byte[] cmd2 = NOOP.encode();
- byte[] stream = new byte[cmd1.length + cmd2.length];
- System.arraycopy( cmd1, 0, stream, 0, cmd1.length );
- System.arraycopy( cmd2, 0, stream, cmd1.length, cmd2.length );
- DataInputStream is = new DataInputStream( new ByteArrayInputStream( stream ) );
- Command bye = decode( is );
- assertNotNull( bye );
- assertThat( bye.getCommandType(), is( BYE_ACK ) );
- Command noop = decode( is );
- assertNotNull( noop );
- assertThat( noop.getCommandType(), is( NOOP ) );
- }
-}
diff --git a/surefire-booter/pom.xml b/surefire-booter/pom.xml
index 1fa5045..6ba9af1 100644
--- a/surefire-booter/pom.xml
+++ b/surefire-booter/pom.xml
@@ -36,6 +36,30 @@
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-api</artifactId>
<version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>maven-shared-utils</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-extensions-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>maven-shared-utils</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
@@ -73,22 +97,35 @@
<build>
<plugins>
<plugin>
- <groupId>org.jacoco</groupId>
- <artifactId>jacoco-maven-plugin</artifactId>
+ <artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
- <id>jacoco-instrumentation</id>
+ <id>build-test-classpath</id>
+ <phase>generate-sources</phase>
<goals>
- <goal>instrument</goal>
+ <goal>build-classpath</goal>
</goals>
+ <configuration>
+ <includeScope>test</includeScope>
+ <outputFile>target/test-classpath/cp.txt</outputFile>
+ </configuration>
</execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <executions>
<execution>
- <id>restore-classes</id>
+ <id>jacoco-agent</id>
<goals>
- <goal>restore-instrumented-classes</goal>
+ <goal>prepare-agent</goal>
</goals>
</execution>
</executions>
+ <configuration>
+ <propertyName>jacoco.agent</propertyName>
+ </configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
@@ -100,7 +137,7 @@
</dependency>
</dependencies>
<configuration>
- <argLine>${jvm.args.tests}</argLine>
+ <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
<includes>
<include>**/JUnit4SuiteTest.java</include>
</includes>
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
index fc570f0..fa664be 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
@@ -58,4 +58,5 @@ public final class BooterConstants
public static final String SYSTEM_EXIT_TIMEOUT = "systemExitTimeout";
public static final String PLUGIN_PID = "pluginPid";
public static final String PROCESS_CHECKER = "processChecker";
+ public static final String FORK_NODE_CONNECTION_STRING = "forkNodeConnectionString";
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
index b091679..4b31db8 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -58,6 +58,11 @@ public class BooterDeserializer
properties = SystemPropertyManager.loadProperties( inputStream );
}
+ public String getForkNodeConnectionString()
+ {
+ return properties.getProperty( FORK_NODE_CONNECTION_STRING );
+ }
+
/**
* @return PID of Maven process where plugin is executed; or null if PID could not be determined.
*/
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
similarity index 83%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
rename to surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index b51f713..a197157 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -20,10 +20,13 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.booter.spi.MasterProcessCommandNoMagicNumberException;
+import org.apache.maven.surefire.booter.spi.MasterProcessUnknownCommandException;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
-import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Iterator;
@@ -47,7 +50,6 @@ import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
import static org.apache.maven.surefire.booter.MasterProcessCommand.TEST_SET_FINISHED;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThread;
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
@@ -58,12 +60,10 @@ import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
-public final class CommandReader
+public final class CommandReader implements CommandChainReader
{
private static final String LAST_TEST_SYMBOL = "";
- private static final CommandReader READER = new CommandReader();
-
private final Queue<BiProperty<MasterProcessCommand, CommandListener>> listeners = new ConcurrentLinkedQueue<>();
private final Thread commandThread = newDaemonThread( new CommandRunnable(), "surefire-forkedjvm-command-thread" );
@@ -76,38 +76,24 @@ public final class CommandReader
private final CopyOnWriteArrayList<String> testClasses = new CopyOnWriteArrayList<>();
- private volatile Shutdown shutdown;
-
- private int iteratedCount;
-
- private volatile ConsoleLogger logger = new NullConsoleLogger();
+ private final MasterProcessChannelDecoder decoder;
- private CommandReader()
- {
- }
+ private final Shutdown shutdown;
- public static CommandReader getReader()
- {
- final CommandReader reader = READER;
- if ( reader.state.compareAndSet( NEW, RUNNABLE ) )
- {
- reader.commandThread.start();
- }
- return reader;
- }
+ private final ConsoleLogger logger;
- public CommandReader setShutdown( Shutdown shutdown )
- {
- this.shutdown = shutdown;
- return this;
- }
+ private int iteratedCount;
- public CommandReader setLogger( ConsoleLogger logger )
+ public CommandReader( MasterProcessChannelDecoder decoder, Shutdown shutdown, ConsoleLogger logger )
{
+ this.decoder = requireNonNull( decoder, "null decoder" );
+ this.shutdown = requireNonNull( shutdown, "null Shutdown config" );
this.logger = requireNonNull( logger, "null logger" );
- return this;
+ state.set( RUNNABLE );
+ commandThread.start();
}
+ @Override
public boolean awaitStarted()
throws TestSetFailedException
{
@@ -143,11 +129,13 @@ public final class CommandReader
addListener( RUN_CLASS, listener );
}
+ @Override
public void addTestsFinishedListener( CommandListener listener )
{
addListener( TEST_SET_FINISHED, listener );
}
+ @Override
public void addSkipNextTestsListener( CommandListener listener )
{
addListener( SKIP_SINCE_NEXT_TEST, listener );
@@ -173,6 +161,7 @@ public final class CommandReader
listeners.add( new BiProperty<>( cmd, listener ) );
}
+ @Override
public void removeListener( CommandListener listener )
{
for ( Iterator<BiProperty<MasterProcessCommand, CommandListener>> it = listeners.iterator(); it.hasNext(); )
@@ -374,54 +363,43 @@ public final class CommandReader
public void run()
{
CommandReader.this.startMonitor.countDown();
- DataInputStream stdIn = new DataInputStream( System.in );
boolean isTestSetFinished = false;
try
{
while ( CommandReader.this.state.get() == RUNNABLE )
{
- Command command = decode( stdIn );
- if ( command == null )
- {
- String errorMessage = "[SUREFIRE] std/in stream corrupted: first sequence not recognized";
- DumpErrorSingleton.getSingleton().dumpStreamText( errorMessage );
- logger.error( errorMessage );
- break;
- }
- else
+ Command command = CommandReader.this.decoder.decode();
+ switch ( command.getCommandType() )
{
- switch ( command.getCommandType() )
- {
- case RUN_CLASS:
- String test = command.getData();
- boolean inserted = CommandReader.this.insertToQueue( test );
- if ( inserted )
- {
- CommandReader.this.wakeupIterator();
- callListeners( command );
- }
- break;
- case TEST_SET_FINISHED:
- CommandReader.this.makeQueueFull();
- isTestSetFinished = true;
- CommandReader.this.wakeupIterator();
- callListeners( command );
- break;
- case SHUTDOWN:
- CommandReader.this.makeQueueFull();
+ case RUN_CLASS:
+ String test = command.getData();
+ boolean inserted = CommandReader.this.insertToQueue( test );
+ if ( inserted )
+ {
CommandReader.this.wakeupIterator();
callListeners( command );
+ }
+ break;
+ case TEST_SET_FINISHED:
+ CommandReader.this.makeQueueFull();
+ isTestSetFinished = true;
+ CommandReader.this.wakeupIterator();
+ callListeners( command );
+ break;
+ case SHUTDOWN:
+ CommandReader.this.makeQueueFull();
+ CommandReader.this.wakeupIterator();
+ callListeners( command );
break;
case BYE_ACK:
callListeners( command );
- // After SHUTDOWN no more commands can come.
+ // After SHUTDOWN no more commands can come.
// Hence, do NOT go back to blocking in I/O.
CommandReader.this.state.set( TERMINATED );
break;
- default:
- callListeners( command );
- break;
- }
+ default:
+ callListeners( command );
+ break;
}
}
}
@@ -439,6 +417,11 @@ public final class CommandReader
// does not go to finally for non-default config: Shutdown.EXIT or Shutdown.KILL
}
}
+ catch ( MasterProcessCommandNoMagicNumberException | MasterProcessUnknownCommandException e )
+ {
+ DumpErrorSingleton.getSingleton().dumpStreamException( e );
+ CommandReader.this.logger.error( e );
+ }
catch ( IOException e )
{
CommandReader.this.state.set( TERMINATED );
@@ -447,7 +430,7 @@ public final class CommandReader
{
String msg = "[SUREFIRE] std/in stream corrupted";
DumpErrorSingleton.getSingleton().dumpStreamException( e, msg );
- logger.error( msg, e );
+ CommandReader.this.logger.error( msg, e );
}
}
finally
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
index 2701221..4e0bf99 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -20,9 +20,14 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoderFactory;
+import org.apache.maven.surefire.providerapi.CommandListener;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory;
import org.apache.maven.surefire.testset.TestSetFailedException;
import java.io.File;
@@ -37,6 +42,7 @@ import java.lang.reflect.InvocationTargetException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.ServiceLoader;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.Semaphore;
@@ -73,7 +79,6 @@ public final class ForkedBooter
private static final String LAST_DITCH_SHUTDOWN_THREAD = "surefire-forkedjvm-last-ditch-daemon-shutdown-thread-";
private static final String PING_THREAD = "surefire-forkedjvm-ping-";
- private final CommandReader commandReader = CommandReader.getReader();
private final ForkedChannelEncoder eventChannel = new ForkedChannelEncoder( System.out );
private final Semaphore exitBarrier = new Semaphore( 0 );
@@ -83,6 +88,7 @@ public final class ForkedBooter
private ScheduledThreadPoolExecutor jvmTerminator;
private ProviderConfiguration providerConfiguration;
private ForkingReporterFactory forkingReporterFactory;
+ private volatile CommandReader commandReader;
private StartupConfiguration startupConfiguration;
private Object testSet;
@@ -109,6 +115,10 @@ public final class ForkedBooter
forkingReporterFactory = createForkingReporterFactory();
ConsoleLogger logger = (ConsoleLogger) forkingReporterFactory.createReporter();
+ String communicationConfig = startupConfiguration.getInterProcessChannelConfiguration();
+ MasterProcessChannelDecoder decoder = lookupDecoderFactory().createDecoder( communicationConfig, logger );
+ commandReader = new CommandReader( decoder, providerConfiguration.getShutdown(), logger );
+
pingScheduler = isDebugging() ? null : listenToShutdownCommands( booterDeserializer.getPluginPid(), logger );
systemExitTimeoutInSeconds = providerConfiguration.systemExitTimeout( DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
@@ -162,7 +172,7 @@ public final class ForkedBooter
}
else if ( readTestsFromCommandReader )
{
- return new LazyTestsToRun( eventChannel );
+ return new LazyTestsToRun( eventChannel, commandReader );
}
return null;
}
@@ -418,7 +428,9 @@ public final class ForkedBooter
private SurefireProvider createProviderInCurrentClassloader( ForkingReporterFactory reporterManagerFactory )
{
- BaseProviderFactory bpf = new BaseProviderFactory( reporterManagerFactory, true );
+ BaseProviderFactory bpf = new BaseProviderFactory( true );
+ bpf.setReporterFactory( reporterManagerFactory );
+ bpf.setCommandReader( commandReader );
bpf.setTestRequest( providerConfiguration.getTestSuiteDefinition() );
bpf.setReporterConfiguration( providerConfiguration.getReporterConfiguration() );
bpf.setForkedChannelEncoder( eventChannel );
@@ -430,12 +442,30 @@ public final class ForkedBooter
bpf.setDirectoryScannerParameters( providerConfiguration.getDirScannerParams() );
bpf.setMainCliOptions( providerConfiguration.getMainCliOptions() );
bpf.setSkipAfterFailureCount( providerConfiguration.getSkipAfterFailureCount() );
- bpf.setShutdown( providerConfiguration.getShutdown() );
bpf.setSystemExitTimeout( providerConfiguration.getSystemExitTimeout() );
String providerClass = startupConfiguration.getActualClassName();
return (SurefireProvider) instantiateOneArg( classLoader, providerClass, ProviderParameters.class, bpf );
}
+ private static MasterProcessChannelDecoderFactory lookupDecoderFactory()
+ {
+ MasterProcessChannelDecoderFactory defaultDecoderFactory = null;
+ MasterProcessChannelDecoderFactory customDecoderFactory = null;
+ for ( MasterProcessChannelDecoderFactory decoderFactory : ServiceLoader.load(
+ MasterProcessChannelDecoderFactory.class ) )
+ {
+ if ( decoderFactory.getClass() == DefaultMasterProcessChannelDecoderFactory.class )
+ {
+ defaultDecoderFactory = decoderFactory;
+ }
+ else
+ {
+ customDecoderFactory = decoderFactory;
+ }
+ }
+ return defaultDecoderFactory == null ? customDecoderFactory : defaultDecoderFactory;
+ }
+
/**
* This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and
* then calls the Surefire class' run method. <br> The system exit code will be 1 if an exception is thrown.
@@ -465,6 +495,8 @@ public final class ForkedBooter
{
DumpErrorSingleton.getSingleton().dumpException( t );
t.printStackTrace();
+ StackTraceWriter stack = new LegacyPojoStackTraceWriter( "test subsystem", "no method", t );
+ booter.eventChannel.consoleErrorLog( stack, false );
booter.cancelPingScheduler();
booter.exit1();
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
index 9d0b2e0..ada3384 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
@@ -25,7 +25,6 @@ import java.util.Iterator;
import org.apache.maven.surefire.util.CloseableIterator;
import org.apache.maven.surefire.util.TestsToRun;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.util.ReflectionUtils.loadClass;
/**
@@ -44,23 +43,24 @@ final class LazyTestsToRun
extends TestsToRun
{
private final ForkedChannelEncoder eventChannel;
+ private final CommandReader commandReader;
/**
* C'tor
*
* @param eventChannel the output stream to use when requesting new new tests
*/
- LazyTestsToRun( ForkedChannelEncoder eventChannel )
+ LazyTestsToRun( ForkedChannelEncoder eventChannel, CommandReader commandReader )
{
super( Collections.<Class<?>>emptySet() );
-
this.eventChannel = eventChannel;
+ this.commandReader = commandReader;
}
private final class BlockingIterator
implements Iterator<Class<?>>
{
- private final Iterator<String> it = getReader().getIterableClasses( eventChannel ).iterator();
+ private final Iterator<String> it = commandReader.getIterableClasses( eventChannel ).iterator();
@Override
public boolean hasNext()
@@ -132,7 +132,7 @@ final class LazyTestsToRun
*/
private Iterator<Class<?>> newWeakIterator()
{
- final Iterator<String> it = getReader().iterated();
+ final Iterator<String> it = commandReader.iterated();
return new CloseableIterator<Class<?>>()
{
@Override
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
index c7379e4..caa26d2 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
@@ -96,7 +96,6 @@ public class ProviderConfiguration
return reporterConfiguration;
}
-
public boolean isFailIfNoTests()
{
return failIfNoTests;
@@ -107,7 +106,6 @@ public class ProviderConfiguration
return dirScannerParams.getTestClassesDirectory();
}
-
public DirectoryScannerParameters getDirScannerParams()
{
return dirScannerParams;
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderFactory.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderFactory.java
index 41badfd..614ff92 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderFactory.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderFactory.java
@@ -99,7 +99,8 @@ public class ProviderFactory
final ClassLoader systemClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader( classLoader );
// Note: Duplicated in ForkedBooter#createProviderInCurrentClassloader
- Object o = surefireReflector.createBooterConfiguration( classLoader, reporterManagerFactory, isInsideFork );
+ Object o = surefireReflector.createBooterConfiguration( classLoader, isInsideFork );
+ surefireReflector.setReporterFactoryAware( o, reporterManagerFactory );
surefireReflector.setTestSuiteDefinitionAware( o, providerConfiguration.getTestSuiteDefinition() );
surefireReflector.setProviderPropertiesAware( o, providerConfiguration.getProviderProperties() );
surefireReflector.setReporterConfigurationAware( o, providerConfiguration.getReporterConfiguration() );
@@ -109,7 +110,6 @@ public class ProviderFactory
surefireReflector.setIfDirScannerAware( o, providerConfiguration.getDirScannerParams() );
surefireReflector.setMainCliOptions( o, providerConfiguration.getMainCliOptions() );
surefireReflector.setSkipAfterFailureCount( o, providerConfiguration.getSkipAfterFailureCount() );
- surefireReflector.setShutdown( o, providerConfiguration.getShutdown() );
if ( isInsideFork )
{
surefireReflector.setSystemExitTimeout( o, providerConfiguration.getSystemExitTimeout() );
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
index 0bbe988..44eb5b7 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
@@ -50,6 +50,11 @@ public class StartupConfiguration
this.processChecker = processChecker;
}
+ public String getInterProcessChannelConfiguration()
+ {
+ return "pipe:std:in";
+ }
+
public boolean isProviderMainClass()
{
return providerClassName.endsWith( "#main" );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
similarity index 81%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
rename to surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
index 5cc1415..20ff510 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
@@ -19,8 +19,6 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.report.ReporterConfiguration;
@@ -46,7 +44,6 @@ import static java.util.Collections.checkedList;
import static org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
-import static org.apache.maven.surefire.util.ReflectionUtils.instantiateTwoArgs;
import static org.apache.maven.surefire.util.ReflectionUtils.invokeGetter;
import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
import static org.apache.maven.surefire.util.ReflectionUtils.invokeSetter;
@@ -59,7 +56,7 @@ import static org.apache.maven.surefire.util.ReflectionUtils.newInstance;
*
* @author Kristian Rosenvold
*/
-public class SurefireReflector
+public final class SurefireReflector
{
private final ClassLoader surefireClassLoader;
@@ -69,21 +66,11 @@ public class SurefireReflector
private final Class<?> testArtifactInfo;
- private final Class<?> testArtifactInfoAware;
-
private final Class<?> directoryScannerParameters;
private final Class<?> runOrderParameters;
- private final Class<?> directoryScannerParametersAware;
-
- private final Class<?> testSuiteDefinitionAware;
-
- private final Class<?> testClassLoaderAware;
-
- private final Class<?> reporterConfigurationAware;
-
- private final Class<?> providerPropertiesAware;
+ private final Class<?> baseProviderFactory;
private final Class<?> runResult;
@@ -93,12 +80,8 @@ public class SurefireReflector
private final Class<?> testListResolver;
- private final Class<?> mainCliOptions;
-
private final Class<Enum> commandLineOptionsClass;
- private final Class<?> shutdownAwareClass;
-
private final Class<Enum> shutdownClass;
@SuppressWarnings( "unchecked" )
@@ -110,22 +93,14 @@ public class SurefireReflector
reporterConfiguration = surefireClassLoader.loadClass( ReporterConfiguration.class.getName() );
testRequest = surefireClassLoader.loadClass( TestRequest.class.getName() );
testArtifactInfo = surefireClassLoader.loadClass( TestArtifactInfo.class.getName() );
- testArtifactInfoAware = surefireClassLoader.loadClass( TestArtifactInfoAware.class.getName() );
directoryScannerParameters = surefireClassLoader.loadClass( DirectoryScannerParameters.class.getName() );
runOrderParameters = surefireClassLoader.loadClass( RunOrderParameters.class.getName() );
- directoryScannerParametersAware =
- surefireClassLoader.loadClass( DirectoryScannerParametersAware.class.getName() );
- testSuiteDefinitionAware = surefireClassLoader.loadClass( TestRequestAware.class.getName() );
- testClassLoaderAware = surefireClassLoader.loadClass( SurefireClassLoadersAware.class.getName() );
- reporterConfigurationAware = surefireClassLoader.loadClass( ReporterConfigurationAware.class.getName() );
- providerPropertiesAware = surefireClassLoader.loadClass( ProviderPropertiesAware.class.getName() );
+ baseProviderFactory = surefireClassLoader.loadClass( BaseProviderFactory.class.getName() );
reporterFactory = surefireClassLoader.loadClass( ReporterFactory.class.getName() );
runResult = surefireClassLoader.loadClass( RunResult.class.getName() );
booterParameters = surefireClassLoader.loadClass( ProviderParameters.class.getName() );
testListResolver = surefireClassLoader.loadClass( TestListResolver.class.getName() );
- mainCliOptions = surefireClassLoader.loadClass( MainCliOptionsAware.class.getName() );
commandLineOptionsClass = (Class<Enum>) surefireClassLoader.loadClass( CommandLineOption.class.getName() );
- shutdownAwareClass = surefireClassLoader.loadClass( ShutdownAware.class.getName() );
shutdownClass = (Class<Enum>) surefireClassLoader.loadClass( Shutdown.class.getName() );
}
catch ( ClassNotFoundException e )
@@ -227,11 +202,9 @@ public class SurefireReflector
return newInstance( constructor, reporterConfig.getReportsDirectory(), reporterConfig.isTrimStackTrace() );
}
- public Object createBooterConfiguration( ClassLoader surefireClassLoader, Object factoryInstance,
- boolean insideFork )
+ public Object createBooterConfiguration( ClassLoader surefireClassLoader, boolean insideFork )
{
- return instantiateTwoArgs( surefireClassLoader, BaseProviderFactory.class.getName(),
- reporterFactory, factoryInstance, boolean.class, insideFork );
+ return instantiateOneArg( surefireClassLoader, BaseProviderFactory.class.getName(), boolean.class, insideFork );
}
public Object instantiateProvider( String providerClassName, Object booterParameters )
@@ -241,7 +214,7 @@ public class SurefireReflector
public void setIfDirScannerAware( Object o, DirectoryScannerParameters dirScannerParams )
{
- if ( directoryScannerParametersAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setDirectoryScannerParameters( o, dirScannerParams );
}
@@ -249,7 +222,7 @@ public class SurefireReflector
public void setMainCliOptions( Object o, List<CommandLineOption> options )
{
- if ( mainCliOptions.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
List<Enum> newOptions = checkedList( new ArrayList<Enum>( options.size() ), commandLineOptionsClass );
Collection<Integer> ordinals = toOrdinals( options );
@@ -271,15 +244,12 @@ public class SurefireReflector
public void setShutdown( Object o, Shutdown shutdown )
{
- if ( shutdownAwareClass.isAssignableFrom( o.getClass() ) )
+ for ( Enum e : shutdownClass.getEnumConstants() )
{
- for ( Enum e : shutdownClass.getEnumConstants() )
+ if ( shutdown.ordinal() == e.ordinal() )
{
- if ( shutdown.ordinal() == e.ordinal() )
- {
- invokeSetter( o, "setShutdown", shutdownClass, e );
- break;
- }
+ invokeSetter( o, "setShutdown", shutdownClass, e );
+ break;
}
}
}
@@ -303,7 +273,7 @@ public class SurefireReflector
public void setTestSuiteDefinitionAware( Object o, TestRequest testSuiteDefinition2 )
{
- if ( testSuiteDefinitionAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestSuiteDefinition( o, testSuiteDefinition2 );
}
@@ -317,7 +287,7 @@ public class SurefireReflector
public void setProviderPropertiesAware( Object o, Map<String, String> properties )
{
- if ( providerPropertiesAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setProviderProperties( o, properties );
}
@@ -330,7 +300,7 @@ public class SurefireReflector
public void setReporterConfigurationAware( Object o, ReporterConfiguration reporterConfiguration1 )
{
- if ( reporterConfigurationAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setReporterConfiguration( o, reporterConfiguration1 );
}
@@ -344,7 +314,7 @@ public class SurefireReflector
public void setTestClassLoaderAware( Object o, ClassLoader testClassLoader )
{
- if ( testClassLoaderAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestClassLoader( o, testClassLoader );
}
@@ -358,7 +328,7 @@ public class SurefireReflector
public void setTestArtifactInfoAware( Object o, TestArtifactInfo testArtifactInfo1 )
{
- if ( testArtifactInfoAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestArtifactInfo( o, testArtifactInfo1 );
}
@@ -370,6 +340,19 @@ public class SurefireReflector
invokeSetter( o, "setTestArtifactInfo", this.testArtifactInfo, param );
}
+ public void setReporterFactoryAware( Object o, Object reporterFactory )
+ {
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
+ {
+ setReporterFactory( o, reporterFactory );
+ }
+ }
+
+ void setReporterFactory( Object o, Object reporterFactory )
+ {
+ invokeSetter( o, "setReporterFactory", this.reporterFactory, reporterFactory );
+ }
+
private boolean isRunResult( Object o )
{
return runResult.isAssignableFrom( o.getClass() );
@@ -384,17 +367,4 @@ public class SurefireReflector
}
return ordinals;
}
-
- public static Object createConsoleLogger( ConsoleLogger consoleLogger, ClassLoader cl )
- {
- try
- {
- Class<?> decoratorClass = cl.loadClass( ConsoleLoggerDecorator.class.getName() );
- return getConstructor( decoratorClass, Object.class ).newInstance( consoleLogger );
- }
- catch ( Exception e )
- {
- throw new SurefireReflectionException( e );
- }
- }
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java
new file mode 100644
index 0000000..4b363ee
--- /dev/null
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java
@@ -0,0 +1,162 @@
+package org.apache.maven.surefire.booter.spi;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+public class DefaultMasterProcessChannelDecoder implements MasterProcessChannelDecoder
+{
+ private final InputStream is;
+ private final ConsoleLogger logger;
+
+ public DefaultMasterProcessChannelDecoder( InputStream is, ConsoleLogger logger )
+ {
+ this.is = is;
+ this.logger = logger;
+ }
+
+ protected boolean hasData( String opcode )
+ {
+ MasterProcessCommand cmd = MasterProcessCommand.byOpcode( opcode );
+ return cmd == null || cmd.hasDataType();
+ }
+
+ @SuppressWarnings( "checkstyle:innerassignment" )
+ @Override
+ public Command decode() throws IOException
+ {
+ List<String> tokens = new ArrayList<>();
+ StringBuilder frame = new StringBuilder();
+ boolean frameStarted = false;
+ boolean frameFinished = false;
+ for ( int r; ( r = is.read() ) != -1 ; )
+ {
+ char c = (char) r;
+ if ( frameFinished && c == '\n' )
+ {
+ continue;
+ }
+
+ if ( !frameStarted )
+ {
+ if ( c == ':' )
+ {
+ frameStarted = true;
+ frameFinished = false;
+ frame.setLength( 0 );
+ tokens.clear();
+ continue;
+ }
+ }
+ else if ( !frameFinished )
+ {
+ boolean isColon = c == ':';
+ if ( isColon || c == '\n' || c == '\r' )
+ {
+ tokens.add( frame.toString() );
+ frame.setLength( 0 );
+ }
+ else
+ {
+ frame.append( c );
+ }
+ boolean isFinishedFrame = isTokenComplete( tokens );
+ if ( isFinishedFrame )
+ {
+ frameFinished = true;
+ frameStarted = false;
+ break;
+ }
+ }
+
+ boolean removed = removeUnsynchronizedTokens( tokens, logger );
+ if ( removed && tokens.isEmpty() )
+ {
+ frameStarted = false;
+ frameFinished = true;
+ }
+ }
+
+ if ( tokens.size() <= 1 )
+ {
+ throw new MasterProcessCommandNoMagicNumberException( frame.toString() );
+ }
+ if ( tokens.size() == 2 )
+ {
+ return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ) );
+ }
+ else if ( tokens.size() == 3 )
+ {
+ return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ), tokens.get( 2 ) );
+ }
+ else
+ {
+ throw new MasterProcessUnknownCommandException( frame.toString() );
+ }
+ }
+
+ private boolean isTokenComplete( List<String> tokens )
+ {
+ if ( tokens.size() >= 2 )
+ {
+ return hasData( tokens.get( 1 ) ) == ( tokens.size() == 3 );
+ }
+ return false;
+ }
+
+ private boolean removeUnsynchronizedTokens( Collection<String> tokens, ConsoleLogger logger )
+ {
+ boolean removed = false;
+ for ( Iterator<String> it = tokens.iterator(); it.hasNext(); )
+ {
+ String token = it.next();
+ if ( token.equals( "maven-surefire-std-out" ) )
+ {
+ break;
+ }
+ removed = true;
+ it.remove();
+ logger.error( "Forked JVM could not synchronize the '" + token + "' token with preamble sequence." );
+ }
+ return removed;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
similarity index 50%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
index eddebed..f7e7911 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,28 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+public class DefaultMasterProcessChannelDecoderFactory
+ implements MasterProcessChannelDecoderFactory
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ @Override
+ public MasterProcessChannelDecoder createDecoder( String channelConfig, ConsoleLogger logger ) throws IOException
+ {
+ if ( "pipe:std:in".equals( channelConfig ) )
+ {
+ return new DefaultMasterProcessChannelDecoder( System.in, logger );
+ }
+ else
+ {
+ throw new IOException( "Unknown chanel configuration string " + channelConfig );
+ }
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
similarity index 65%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
index eddebed..261969e 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,20 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
+ * No magic number recognized in the command line, see the JavaDoc in {@link MasterProcessCommand}.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public class MasterProcessCommandNoMagicNumberException extends IOException
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ MasterProcessCommandNoMagicNumberException( String line )
+ {
+ super( "No magic # recognized in the line '" + line + "'" );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
similarity index 63%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
index eddebed..11cab97 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
+ * No {@link MasterProcessCommand command} recognized according to the opcode
+ * encapsulated in the command line, see the JavaDoc in {@link MasterProcessCommand}.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public class MasterProcessUnknownCommandException extends IOException
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ MasterProcessUnknownCommandException( String line )
+ {
+ super( "Unrecognized command found '" + line + "'" );
+ }
}
diff --git a/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory b/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory
new file mode 100644
index 0000000..2b44ee1
--- /dev/null
+++ b/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoderFactory
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
similarity index 86%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 40c0243..096cfb4 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -19,6 +19,10 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
import org.junit.After;
import org.junit.Before;
@@ -29,7 +33,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
@@ -39,8 +42,7 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
+import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -61,7 +63,6 @@ public class CommandReaderTest
private static final long TEST_TIMEOUT = 15_000L;
private final BlockingQueue<Byte> blockingStream = new LinkedBlockingQueue<>();
- private InputStream realInputStream;
private CommandReader reader;
static class A
@@ -83,18 +84,19 @@ public class CommandReaderTest
@Before
public void init()
{
+ //noinspection ResultOfMethodCallIgnored
Thread.interrupted();
- realInputStream = System.in;
+ InputStream realInputStream = new SystemInputStream();
addTestToPipeline( getClass().getName() );
- System.setIn( new SystemInputStream() );
- reader = CommandReader.getReader();
+ ConsoleLogger logger = new NullConsoleLogger();
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( realInputStream, logger );
+ reader = new CommandReader( decoder, Shutdown.DEFAULT, logger );
}
@After
public void deinit()
{
reader.stop();
- System.setIn( realInputStream );
}
@Test
@@ -242,24 +244,20 @@ public class CommandReaderTest
private void addTestToPipeline( String cls )
{
- byte[] clazz = cls.getBytes( ISO_8859_1 );
- ByteBuffer buffer = ByteBuffer.allocate( 8 + clazz.length ).putInt(
- MasterProcessCommand.RUN_CLASS.getId() ).putInt( clazz.length ).put( clazz );
- buffer.rewind();
- for ( ; buffer.hasRemaining(); )
+ String cmd = ":maven-surefire-std-out:"
+ + MasterProcessCommand.RUN_CLASS.getOpcode() + ':' + cls + '\n';
+ for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
{
- blockingStream.add( buffer.get() );
+ blockingStream.add( cmdByte );
}
}
private void addEndOfPipeline()
{
- ByteBuffer buffer = ByteBuffer.allocate( 8 ).putInt( MasterProcessCommand.TEST_SET_FINISHED.getId() ).putInt(
- 0 );
- buffer.rewind();
- for ( ; buffer.hasRemaining(); )
+ String cmd = ":maven-surefire-std-out:" + MasterProcessCommand.TEST_SET_FINISHED.getOpcode() + '\n';
+ for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
{
- blockingStream.add( buffer.get() );
+ blockingStream.add( cmdByte );
}
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/DefaultMasterProcessChannelDecoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/DefaultMasterProcessChannelDecoderTest.java
new file mode 100644
index 0000000..debab05
--- /dev/null
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/DefaultMasterProcessChannelDecoderTest.java
@@ -0,0 +1,148 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.TestCase;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Tests for {@link DefaultMasterProcessChannelDecoder}.
+ */
+public class DefaultMasterProcessChannelDecoderTest
+ extends TestCase
+{
+ public void testDataToByteArrayAndBack() throws IOException
+ {
+ for ( MasterProcessCommand commandType : MasterProcessCommand.values() )
+ {
+ switch ( commandType )
+ {
+ case RUN_CLASS:
+ assertEquals( String.class, commandType.getDataType() );
+ byte[] encoded = commandType.encode( "pkg.Test" );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:run-testclass:pkg.Test:" );
+ byte[] line = addNL( encoded, '\n' );
+ InputStream is = new ByteArrayInputStream( line );
+ DefaultMasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertThat( command.getData(), is( "pkg.Test" ) );
+ break;
+ case TEST_SET_FINISHED:
+ assertThat( commandType ).isSameAs( Command.TEST_SET_FINISHED.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:testset-finished:" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case SKIP_SINCE_NEXT_TEST:
+ assertThat( commandType ).isSameAs( Command.SKIP_SINCE_NEXT_TEST.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:skip-since-next-test:" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case SHUTDOWN:
+ assertEquals( String.class, commandType.getDataType() );
+ encoded = commandType.encode( Shutdown.EXIT.name() );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:shutdown:EXIT:" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertThat( command.getData(), is( "EXIT" ) );
+ break;
+ case NOOP:
+ assertThat( commandType ).isSameAs( Command.NOOP.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:noop:" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case BYE_ACK:
+ assertThat( commandType ).isSameAs( Command.BYE_ACK.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:bye-ack:" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ default:
+ fail();
+ }
+ }
+ }
+
+ public void testShouldDecodeTwoCommands() throws IOException
+ {
+ String cmd = ":maven-surefire-std-out:bye-ack\n:maven-surefire-std-out:bye-ack:";
+ InputStream is = new ByteArrayInputStream( cmd.getBytes() );
+ DefaultMasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
+
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isEqualTo( BYE_ACK );
+ assertThat( command.getData() ).isNull();
+
+ command = decoder.decode();
+ assertThat( command.getCommandType() ).isEqualTo( BYE_ACK );
+ assertThat( command.getData() ).isNull();
+ }
+
+ private static byte[] addNL( byte[] encoded, char... newLines )
+ {
+ byte[] line = new byte[encoded.length + newLines.length];
+ System.arraycopy( encoded, 0, line, 0, encoded.length );
+ for ( int i = encoded.length, j = 0; i < line.length; i++, j++ )
+ {
+ line[i] = (byte) newLines[j];
+ }
+ return line;
+ }
+}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
similarity index 80%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
index ccb01e3..3b71b36 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
@@ -19,9 +19,9 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-
import java.util.Map;
import org.apache.maven.surefire.report.ReporterConfiguration;
+import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
import org.apache.maven.surefire.testset.RunOrderParameters;
import org.apache.maven.surefire.testset.TestArtifactInfo;
@@ -30,27 +30,28 @@ import org.apache.maven.surefire.testset.TestRequest;
/**
* @author Kristian Rosenvold
*/
-public class Foo
- implements DirectoryScannerParametersAware, TestRequestAware, ProviderPropertiesAware, ReporterConfigurationAware,
- SurefireClassLoadersAware, TestArtifactInfoAware, RunOrderParametersAware
+public class Foo extends BaseProviderFactory
{
- DirectoryScannerParameters directoryScannerParameters;
+ private DirectoryScannerParameters directoryScannerParameters;
- Map<String, String> providerProperties;
+ private Map<String, String> providerProperties;
- ReporterConfiguration reporterConfiguration;
+ private ReporterConfiguration reporterConfiguration;
- ClassLoader surefireClassLoader;
+ private ClassLoader testClassLoader;
- ClassLoader testClassLoader;
+ private TestRequest testRequest;
- TestRequest testRequest;
+ private TestArtifactInfo testArtifactInfo;
- TestArtifactInfo testArtifactInfo;
+ private RunOrderParameters runOrderParameters;
- RunOrderParameters runOrderParameters;
+ private boolean called;
- boolean called = false;
+ Foo()
+ {
+ super( false );
+ }
@Override
public void setDirectoryScannerParameters( DirectoryScannerParameters directoryScanner )
@@ -59,7 +60,6 @@ public class Foo
this.called = true;
}
-
/**
* @return true if it has been called
*/
@@ -86,7 +86,6 @@ public class Foo
public void setClassLoaders( ClassLoader testClassLoader )
{
this.testClassLoader = testClassLoader;
- this.surefireClassLoader = surefireClassLoader;
this.called = true;
}
@@ -110,4 +109,10 @@ public class Foo
this.runOrderParameters = runOrderParameters;
this.called = true;
}
+
+ @Override
+ public void setReporterFactory( ReporterFactory reporterFactory )
+ {
+ called = true;
+ }
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
index e65beb1..24a250b 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
@@ -19,11 +19,14 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.report.StackTraceWriter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@@ -31,18 +34,24 @@ import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.doCallRealMethod;
+import static org.powermock.api.mockito.PowerMockito.doNothing;
import static org.powermock.api.mockito.PowerMockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.verifyNoMoreInteractions;
import static org.powermock.api.mockito.PowerMockito.verifyPrivate;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.reflect.Whitebox.invokeMethod;
+import static org.powermock.reflect.Whitebox.setInternalState;
+import static org.powermock.utils.JavaVersion.JAVA_RECENT;
+import static org.powermock.utils.JavaVersion.JAVA_12;
/**
* PowerMock tests for {@link ForkedBooter}.
*/
@RunWith( PowerMockRunner.class )
-@PrepareForTest( { PpidChecker.class, ForkedBooter.class } )
+@PrepareForTest( { PpidChecker.class, ForkedBooter.class, ForkedChannelEncoder.class } )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
public class ForkedBooterMockTest
{
@Mock
@@ -51,6 +60,21 @@ public class ForkedBooterMockTest
@Mock
private ForkedBooter booter;
+ @Mock
+ private ForkedChannelEncoder eventChannel;
+
+ @Captor
+ private ArgumentCaptor<StackTraceWriter> capturedStackTraceWriter;
+
+ @Captor
+ private ArgumentCaptor<Boolean> capturedBoolean;
+
+ @Captor
+ private ArgumentCaptor<String[]> capturedArgs;
+
+ @Captor
+ private ArgumentCaptor<ForkedBooter> capturedBooter;
+
@Test
public void shouldCheckNewPingMechanism() throws Exception
{
@@ -71,8 +95,6 @@ public class ForkedBooterMockTest
{
PowerMockito.mockStatic( ForkedBooter.class );
- ArgumentCaptor<String[]> capturedArgs = ArgumentCaptor.forClass( String[].class );
- ArgumentCaptor<ForkedBooter> capturedBooter = ArgumentCaptor.forClass( ForkedBooter.class );
doCallRealMethod()
.when( ForkedBooter.class, "run", capturedBooter.capture(), capturedArgs.capture() );
@@ -106,6 +128,13 @@ public class ForkedBooterMockTest
@Test
public void testMainWithError() throws Exception
{
+ //does not work in PowerMock
+ //assumeFalse( JAVA_RECENT.atLeast( JAVA_12 ) );
+ if ( JAVA_RECENT.atLeast( JAVA_12 ) )
+ {
+ return;
+ }
+
PowerMockito.mockStatic( ForkedBooter.class );
doCallRealMethod()
@@ -114,6 +143,13 @@ public class ForkedBooterMockTest
doThrow( new RuntimeException( "dummy exception" ) )
.when( booter, "execute" );
+ doNothing()
+ .when( booter, "setupBooter",
+ any( String.class ), any( String.class ), any( String.class ), any( String.class ) );
+
+ // broken in PowerMock JDK 12
+ setInternalState( booter, "eventChannel", eventChannel );
+
String[] args = new String[]{ "/", "dump", "surefire.properties", "surefire-effective.properties" };
invokeMethod( ForkedBooter.class, "run", booter, args );
@@ -123,6 +159,18 @@ public class ForkedBooterMockTest
verifyPrivate( booter, times( 1 ) )
.invoke( "execute" );
+ verify( eventChannel, times( 1 ) )
+ .consoleErrorLog( capturedStackTraceWriter.capture(), capturedBoolean.capture() );
+ assertThat( capturedStackTraceWriter.getValue() )
+ .isNotNull();
+ assertThat( capturedStackTraceWriter.getValue().smartTrimmedStackTrace() )
+ .isEqualTo( "test subsystem#no method RuntimeException dummy exception" );
+ assertThat( capturedStackTraceWriter.getValue().getThrowable().getTarget() )
+ .isNotNull()
+ .isInstanceOf( RuntimeException.class );
+ assertThat( capturedStackTraceWriter.getValue().getThrowable().getTarget().getMessage() )
+ .isEqualTo( "dummy exception" );
+
verifyPrivate( booter, times( 1 ) )
.invoke( "cancelPingScheduler" );
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/IsolatedClassLoaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/IsolatedClassLoaderTest.java
new file mode 100644
index 0000000..b424526
--- /dev/null
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/IsolatedClassLoaderTest.java
@@ -0,0 +1,66 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.shared.utils.io.FileUtils;
+import org.apache.maven.surefire.providerapi.AbstractProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.net.URL;
+
+import static java.io.File.pathSeparator;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Tests isolated CL.
+ */
+public class IsolatedClassLoaderTest
+{
+ private IsolatedClassLoader classLoader;
+
+ @Before
+ public void prepareClassLoader() throws Exception
+ {
+ classLoader = new IsolatedClassLoader( null, false, "role" );
+
+ String[] files = FileUtils.fileRead( new File( "target/test-classpath/cp.txt" ), "UTF-8" )
+ .split( pathSeparator );
+
+ for ( String file : files )
+ {
+ URL fileUrl = new File( file ).toURL();
+ classLoader.addURL( fileUrl );
+ }
+ }
+
+ @Test
+ public void shouldLoadIsolatedClass() throws Exception
+ {
+ Class<?> isolatedClass = classLoader.loadClass( AbstractProvider.class.getName() );
+ assertThat( isolatedClass, is( notNullValue() ) );
+ assertThat( isolatedClass.getName(), is( AbstractProvider.class.getName() ) );
+ assertThat( isolatedClass, is( not( (Class) AbstractProvider.class ) ) );
+ }
+}
\ No newline at end of file
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
index 75b2ef0..9ef4fce 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
@@ -35,13 +35,17 @@ public class JUnit4SuiteTest extends TestCase
public static Test suite()
{
TestSuite suite = new TestSuite();
+ suite.addTest( new JUnit4TestAdapter( CommandReaderTest.class ) );
suite.addTest( new JUnit4TestAdapter( PpidCheckerTest.class ) );
suite.addTest( new JUnit4TestAdapter( SystemUtilsTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( IsolatedClassLoaderTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkedBooterTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkedBooterMockTest.class ) );
suite.addTest( new JUnit4TestAdapter( BooterDeserializerTest.class ) );
suite.addTestSuite( ClasspathTest.class );
suite.addTestSuite( PropertiesWrapperTest.class );
+ suite.addTestSuite( DefaultMasterProcessChannelDecoderTest.class );
+ suite.addTestSuite( SurefireReflectorTest.class );
return suite;
}
}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
similarity index 100%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
similarity index 78%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
index 0a006bf..88a4250 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.booter;
*/
import junit.framework.TestCase;
-import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
@@ -31,7 +30,6 @@ import org.apache.maven.surefire.testset.TestArtifactInfo;
import org.apache.maven.surefire.testset.TestListResolver;
import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.RunOrder;
-import org.mockito.ArgumentCaptor;
import java.io.File;
import java.lang.reflect.Method;
@@ -39,38 +37,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
/**
*
*/
public class SurefireReflectorTest
extends TestCase
{
- public void testCreateConsoleLogger()
- {
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- ConsoleLogger consoleLogger = mock( ConsoleLogger.class );
- ConsoleLogger decorator = (ConsoleLogger) SurefireReflector.createConsoleLogger( consoleLogger, cl );
- assertThat( decorator )
- .isNotSameAs( consoleLogger );
-
- assertThat( decorator.isDebugEnabled() ).isFalse();
- when( consoleLogger.isDebugEnabled() ).thenReturn( true );
- assertThat( decorator.isDebugEnabled() ).isTrue();
- verify( consoleLogger, times( 2 ) ).isDebugEnabled();
-
- decorator.info( "msg" );
- ArgumentCaptor<String> argumentMsg = ArgumentCaptor.forClass( String.class );
- verify( consoleLogger, times( 1 ) ).info( argumentMsg.capture() );
- assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
- assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "msg" );
- }
-
public void testShouldCreateFactoryWithoutException()
{
ReporterFactory factory = new ReporterFactory()
@@ -89,10 +61,10 @@ public class SurefireReflectorTest
};
ClassLoader cl = Thread.currentThread().getContextClassLoader();
SurefireReflector reflector = new SurefireReflector( cl );
- BaseProviderFactory baseProviderFactory =
- (BaseProviderFactory) reflector.createBooterConfiguration( cl, factory, true );
- assertNotNull( baseProviderFactory.getReporterFactory() );
- assertSame( factory, baseProviderFactory.getReporterFactory() );
+ BaseProviderFactory bpf = (BaseProviderFactory) reflector.createBooterConfiguration( cl, true );
+ bpf.setReporterFactory( factory );
+ assertNotNull( bpf.getReporterFactory() );
+ assertSame( factory, bpf.getReporterFactory() );
}
public void testSetDirectoryScannerParameters()
@@ -172,6 +144,30 @@ public class SurefireReflectorTest
assertTrue( isCalled( foo ) );
}
+ public void testReporterFactoryAware()
+ {
+ SurefireReflector surefireReflector = getReflector();
+ Object foo = getFoo();
+
+ ReporterFactory reporterFactory = new ReporterFactory()
+ {
+ @Override
+ public RunListener createReporter()
+ {
+ return null;
+ }
+
+ @Override
+ public RunResult close()
+ {
+ return null;
+ }
+ };
+
+ surefireReflector.setReporterFactory( foo, reporterFactory );
+ assertTrue( isCalled( foo ) );
+ }
+
private SurefireReflector getReflector()
{
return new SurefireReflector( this.getClass().getClassLoader() );
diff --git a/surefire-extensions-api/pom.xml b/surefire-extensions-api/pom.xml
index 1e88403..87fcff4 100644
--- a/surefire-extensions-api/pom.xml
+++ b/surefire-extensions-api/pom.xml
@@ -38,11 +38,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.codehaus.plexus</groupId>
- <artifactId>plexus-component-annotations</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
@@ -72,33 +67,20 @@
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
- <id>jacoco-instrumentation</id>
- <!--
- phase: the order of the plugins matters and maven-plugin-plugin must be before jacoco plugin
- -->
- <goals>
- <goal>instrument</goal>
- </goals>
- </execution>
- <execution>
- <id>restore-classes</id>
+ <id>jacoco-agent</id>
<goals>
- <goal>restore-instrumented-classes</goal>
+ <goal>prepare-agent</goal>
</goals>
</execution>
</executions>
+ <configuration>
+ <propertyName>jacoco.agent</propertyName>
+ </configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.apache.maven.surefire</groupId>
- <artifactId>surefire-shadefire</artifactId>
- <version>3.0.0-M4</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
- </dependency>
- </dependencies>
<configuration>
- <argLine>${jvm.args.tests}</argLine>
+ <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
<includes>
<include>**/JUnit4SuiteTest.java</include>
</includes>
@@ -106,8 +88,14 @@
<jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-shadefire</artifactId>
+ <version>3.0.0-M4</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+ </dependency>
+ </dependencies>
</plugin>
</plugins>
</build>
-
</project>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/CommandReader.java
similarity index 64%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/CommandReader.java
index eddebed..8dd9d96 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/CommandReader.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,26 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.booter.Command;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
+ * Stream reader returns bytes which ar finally sent to the forked jvm.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public interface CommandReader
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+
+ /**
+ * Waits for the next command and returns it.
+ *
+ * @return the command, or null if closed
+ */
+ Command readNextCommand() throws IOException;
+ void close();
+ boolean isClosed();
+ void tryFlush() throws IOException;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/EventHandler.java
similarity index 68%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java
rename to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/EventHandler.java
index 994b60d..bcb6c81 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/EventHandler.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,14 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import javax.annotation.Nonnull;
+
/**
- * See the plugin configuration parameter {@code skipAfterFailureCount}.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface FailFastAware
+public interface EventHandler
{
- void setSkipAfterFailureCount( int skipAfterFailureCount );
+ // todo here should be Event object as POJO which separates physical stream representation from the independent
+ // todo Event parser in ForkClient. So the parser should be part of ForkChannel implementation.
+ void handleEvent( @Nonnull String event );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ExecutableCommandline.java
similarity index 53%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
rename to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ExecutableCommandline.java
index cefeb33..b373002 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ExecutableCommandline.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,20 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.testset.DirectoryScannerParameters;
+import javax.annotation.Nonnull;
+import java.util.concurrent.Callable;
/**
- * @author Kristian Rosenvold
+ * todo add javadoc
*/
-interface DirectoryScannerParametersAware
+public interface ExecutableCommandline
{
- void setDirectoryScannerParameters( DirectoryScannerParameters directoryScanner );
+ @Nonnull
+ <T> Callable<Integer> executeCommandLineAsCallable( @Nonnull T cli,
+ @Nonnull CommandReader commands,
+ @Nonnull EventHandler events,
+ StdOutStreamLine stdOut,
+ StdErrStreamLine stdErr,
+ @Nonnull Runnable runAfterProcessTermination )
+ throws Exception;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkChannel.java
similarity index 52%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkChannel.java
index eddebed..62ef9bf 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkChannel.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,24 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * The constructor prepares I/O or throws {@link IOException}. Open channel can be closed and closes all streams.
+ * <br>
+ * The forked JVM uses the {@link #createExecutableCommandline() connection string}.
+ * The executable CLI {@link #createExecutableCommandline()} is using the streams. This method and constructor should
+ * not be blocked while establishing the connection.
*/
-interface MainCliOptionsAware
+public interface ForkChannel extends Closeable
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ String getForkNodeConnectionString();
+
+ @Nonnull
+ ExecutableCommandline createExecutableCommandline() throws IOException;
+
+ @Override
+ void close() throws IOException;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeFactory.java
similarity index 69%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeFactory.java
index eddebed..c054776 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,20 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import javax.annotation.Nonnull;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
- *
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public interface ForkNodeFactory
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ /**
+ * Opens and closes the channel.
+ *
+ * @return specific implementation of the communication channel
+ * @throws IOException if cannot open the channel
+ */
+ @Nonnull ForkChannel createForkChannel() throws IOException;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdErrStreamLine.java
similarity index 82%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java
rename to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdErrStreamLine.java
index c2f5d99..be444ae 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdErrStreamLine.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,9 +20,9 @@ package org.apache.maven.surefire.booter;
*/
/**
- * @author Kristian Rosenvold
+ * The line handler of forked process standard-error.
*/
-interface SurefireClassLoadersAware
+public interface StdErrStreamLine
{
- void setClassLoaders( ClassLoader testClassLoader );
+ void handleLine( String line );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdOutStreamLine.java
similarity index 80%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java
rename to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdOutStreamLine.java
index caedb98..f615764 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StdOutStreamLine.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,10 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.util.Map;
-
/**
- * @author Kristian Rosenvold
+ * The line handler of forked process standard-output.
*/
-interface ProviderPropertiesAware
+public interface StdOutStreamLine
{
- void setProviderProperties( Map<String, String> providerProperties );
+ void handleLine( String line );
}
diff --git a/surefire-extensions-spi/pom.xml b/surefire-extensions-spi/pom.xml
new file mode 100644
index 0000000..95cf3d9
--- /dev/null
+++ b/surefire-extensions-spi/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>surefire-extensions-spi</artifactId>
+ <name>Surefire Extensions SPI</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
similarity index 57%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
rename to surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
index eddebed..5b08d4d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,22 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * The SPI interface, a factory of decoders.
*/
-interface MainCliOptionsAware
+public interface MasterProcessChannelDecoderFactory
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ /**
+ * Decoder factory method.
+ *
+ * @param channelConfig "pipe:std:in" or "tcp://localhost:65035"
+ * @param logger error logger
+ * @return a new instance of decoder
+ */
+ MasterProcessChannelDecoder createDecoder( String channelConfig, ConsoleLogger logger ) throws IOException;
}
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
index b964933..9e5efad 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.junit4;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
import org.apache.maven.surefire.common.junit4.JUnit4TestChecker;
import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
@@ -52,7 +52,6 @@ import java.util.Set;
import static java.lang.reflect.Modifier.isAbstract;
import static java.lang.reflect.Modifier.isInterface;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.createMatchAnyDescriptionFilter;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
@@ -92,14 +91,14 @@ public class JUnit4Provider
private final int rerunFailingTestsCount;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public JUnit4Provider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
scanResult = bootParams.getScanResult();
diff --git a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
index b949baa..c03ea7e 100644
--- a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
+++ b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
@@ -50,7 +50,7 @@ public class JUnit4ProviderTest
private JUnit4Provider getJUnit4Provider()
{
- BaseProviderFactory providerParameters = new BaseProviderFactory( null, true );
+ BaseProviderFactory providerParameters = new BaseProviderFactory( true );
providerParameters.setProviderProperties( new HashMap<String, String>() );
providerParameters.setClassLoaders( getClass().getClassLoader() );
providerParameters.setTestRequest( new TestRequest( null, null, null ) );
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
index 7c74e8b..daabb60 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.junitcore;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
import org.apache.maven.surefire.common.junit4.Notifier;
@@ -46,7 +46,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
@@ -82,14 +81,14 @@ public class JUnitCoreProvider
private final TestListResolver testResolver;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public JUnitCoreProvider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
scanResult = bootParams.getScanResult();
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java
index 8859c19..66f0b85 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/Surefire746Test.java
@@ -110,7 +110,8 @@ public class Surefire746Test
public void surefireIsConfused_ByMultipleIgnore_OnClassLevel() throws Exception
{
ReporterFactory reporterFactory = JUnitCoreTester.defaultNoXml();
- BaseProviderFactory providerParameters = new BaseProviderFactory( reporterFactory, true );
+ BaseProviderFactory providerParameters = new BaseProviderFactory( true );
+ providerParameters.setReporterFactory( reporterFactory );
providerParameters.setReporterConfiguration( new ReporterConfiguration( new File( "" ), false ) );
Map<String, String> junitProps = new HashMap<>();
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
index 14e103a..a8a5fb7 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.testng;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.providerapi.AbstractProvider;
import org.apache.maven.surefire.providerapi.ProviderParameters;
@@ -43,7 +43,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
import static org.apache.maven.surefire.testset.TestListResolver.getEmptyTestListResolver;
import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
@@ -71,14 +70,14 @@ public class TestNGProvider
private final List<CommandLineOption> mainCliOptions;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public TestNGProvider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
runOrderCalculator = bootParams.getRunOrderCalculator();