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/04/08 08:22:09 UTC
[maven-surefire] 01/18: [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 d0c9039e5faf2ff1939f52e7520324ae9d4886cf
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.
---
.github/workflows/maven.yml | 2 +-
Jenkinsfile | 8 +-
.../maven/plugin/failsafe/IntegrationTestMojo.java | 10 +
maven-surefire-common/pom.xml | 16 -
.../plugin/surefire/AbstractSurefireMojo.java | 74 +-
.../maven/plugin/surefire/CommonReflector.java | 18 +-
.../surefire/SurefireDependencyResolver.java | 1 +
.../AbstractClasspathForkConfiguration.java | 7 +-
.../surefire/booterclient/BooterSerializer.java | 5 +-
.../booterclient/ClasspathForkConfiguration.java | 7 +-
.../booterclient/DefaultForkConfiguration.java | 13 +-
.../surefire/booterclient/ForkConfiguration.java | 2 +
.../plugin/surefire/booterclient/ForkStarter.java | 126 ++-
.../booterclient/JarManifestForkConfiguration.java | 7 +-
.../ModularClasspathForkConfiguration.java | 7 +-
...InputStream.java => AbstractCommandReader.java} | 16 +-
...ommandStream.java => DefaultCommandReader.java} | 60 +-
.../DefferedChannelCommandSender.java} | 12 +-
.../lazytestprovider/TestLessInputStream.java | 7 +-
.../lazytestprovider/TestProvidingInputStream.java | 14 +-
.../surefire/booterclient/output/ForkClient.java | 176 +--
.../booterclient/output/ForkedChannelDecoder.java | 352 ------
.../output/ForkedProcessEventNotifier.java | 248 ++++
.../output/ForkedProcessExitErrorListener.java | 4 +-
.../ForkedProcessStackTraceEventListener.java | 6 +-
.../output/NativeStdErrStreamConsumer.java | 8 +-
...stener.java => NativeStdOutStreamConsumer.java} | 24 +-
.../output/ThreadedStreamConsumer.java | 80 +-
.../surefire/extensions/EventConsumerThread.java | 441 ++++++++
.../surefire/extensions/LegacyForkChannel.java | 89 ++
.../surefire/extensions/LegacyForkNodeFactory.java | 24 +-
.../plugin/surefire/extensions/StreamFeeder.java | 203 ++++
.../surefire/extensions/SurefireForkChannel.java | 140 +++
.../extensions/SurefireForkNodeFactory.java | 25 +-
.../AbstractSurefireMojoJava7PlusTest.java | 27 +-
.../plugin/surefire/AbstractSurefireMojoTest.java | 44 +-
.../maven/plugin/surefire/CommonReflectorTest.java | 50 +
.../maven/plugin/surefire/MojoMocklessTest.java | 7 +
.../plugin/surefire/SurefireReflectorTest.java | 71 --
...ooterDeserializerProviderConfigurationTest.java | 8 +-
...BooterDeserializerStartupConfigurationTest.java | 23 +-
.../booterclient/DefaultForkConfigurationTest.java | 48 +-
.../booterclient/ForkConfigurationTest.java | 17 +-
.../surefire/booterclient/ForkStarterTest.java | 17 +-
.../booterclient/ForkingRunListenerTest.java | 194 ++--
.../plugin/surefire/booterclient/MainClass.java | 14 +-
.../ModularClasspathForkConfigurationTest.java | 10 +-
.../TestLessInputStreamBuilderTest.java | 54 +-
.../TestProvidingInputStreamTest.java | 152 ++-
.../booterclient/output/ForkClientTest.java | 938 ++++------------
.../output/ForkedChannelDecoderTest.java | 901 ---------------
.../extensions/ConsoleOutputReporterTest.java | 8 +-
.../extensions/ForkedProcessEventNotifierTest.java | 1183 ++++++++++++++++++++
.../surefire/extensions/StatelessReporterTest.java | 5 +-
.../surefire/extensions/StreamFeederTest.java | 162 +++
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 14 +-
.../maven/surefire/extensions/ForkChannelTest.java | 166 +++
.../StatelessTestsetInfoReporterTest.java | 2 +-
.../maven/plugin/surefire/SurefirePlugin.java | 10 +
pom.xml | 7 +-
.../maven/surefire/booter/BaseProviderFactory.java | 79 +-
.../org/apache/maven/surefire/booter/Command.java | 21 +-
...ocessEvent.java => ForkedProcessEventType.java} | 20 +-
.../surefire/booter/ForkingReporterFactory.java | 5 +-
.../maven/surefire/booter/ForkingRunListener.java | 5 +-
.../surefire/booter/MasterProcessCommand.java | 147 +--
.../surefire/booter/RunOrderParametersAware.java | 30 -
.../surefire/booter/TestArtifactInfoAware.java | 30 -
.../maven/surefire/booter/TestRequestAware.java | 30 -
.../surefire/eventapi/AbstractConsoleEvent.java | 85 ++
.../eventapi/AbstractStandardStreamEvent.java | 93 ++
.../eventapi/AbstractTestControlEvent.java | 95 ++
.../ConsoleDebugEvent.java} | 16 +-
.../maven/surefire/eventapi/ConsoleErrorEvent.java | 87 ++
.../ConsoleInfoEvent.java} | 18 +-
.../ConsoleWarningEvent.java} | 16 +-
.../ControlByeEvent.java} | 57 +-
.../ControlNextTestEvent.java} | 57 +-
.../eventapi/ControlStopOnNextTestEvent.java | 77 ++
.../Event.java} | 32 +-
.../maven/surefire/eventapi/JvmExitErrorEvent.java | 87 ++
.../surefire/eventapi/StandardStreamErrEvent.java | 19 +-
.../StandardStreamErrWithNewLineEvent.java | 19 +-
.../surefire/eventapi/StandardStreamOutEvent.java | 19 +-
.../StandardStreamOutWithNewLineEvent.java | 19 +-
.../surefire/eventapi/SystemPropertyEvent.java | 101 ++
.../eventapi/TestAssumptionFailureEvent.java | 20 +-
.../maven/surefire/eventapi/TestErrorEvent.java | 20 +-
.../maven/surefire/eventapi/TestFailedEvent.java | 20 +-
.../maven/surefire/eventapi/TestSkippedEvent.java | 20 +-
.../maven/surefire/eventapi/TestStartingEvent.java | 20 +-
.../surefire/eventapi/TestSucceededEvent.java | 20 +-
.../surefire/eventapi/TestsetCompletedEvent.java | 20 +-
.../surefire/eventapi/TestsetStartingEvent.java | 20 +-
.../CommandChainReader.java} | 19 +-
.../{booter => providerapi}/CommandListener.java | 4 +-
.../providerapi/MasterProcessChannelDecoder.java | 48 +
.../providerapi/MasterProcessChannelEncoder.java | 84 ++
.../surefire/providerapi/ProviderParameters.java | 8 +-
.../apache/maven/surefire/report/ReportEntry.java | 2 +-
.../maven/surefire/report/SimpleReportEntry.java | 2 +
.../org/apache/maven/surefire/suite/RunResult.java | 2 +-
.../maven/surefire/testset/TestListResolver.java | 2 +-
.../maven/surefire/util/ReflectionUtils.java | 31 +-
.../util/internal/DaemonThreadFactory.java | 35 +-
.../java/org/apache/maven/JUnit4SuiteTest.java | 10 +-
.../surefire/booter/ForkingRunListenerTest.java | 25 +-
.../surefire/booter/MasterProcessCommandTest.java | 164 ---
.../surefire/booter/SurefireReflectorTest.java | 198 ----
surefire-booter/pom.xml | 39 +-
.../maven/surefire/booter/BooterConstants.java | 1 +
.../maven/surefire/booter/BooterDeserializer.java | 14 +
.../apache/maven/surefire/booter/Classpath.java | 13 +-
.../maven/surefire/booter/CommandReader.java | 130 +--
.../apache/maven/surefire/booter/ForkedBooter.java | 78 +-
.../maven/surefire/booter/LazyTestsToRun.java | 13 +-
.../surefire/booter/ProviderConfiguration.java | 2 -
.../maven/surefire/booter/ProviderFactory.java | 4 +-
.../surefire/booter/StartupConfiguration.java | 22 +-
.../maven/surefire/booter/SurefireReflector.java | 120 +-
.../spi/LegacyMasterProcessChannelDecoder.java | 190 ++++
.../spi/LegacyMasterProcessChannelEncoder.java | 180 +--
...LegacyMasterProcessChannelProcessorFactory.java | 72 ++
...refireMasterProcessChannelProcessorFactory.java | 90 ++
...refire.spi.MasterProcessChannelProcessorFactory | 32 +-
.../surefire/booter/BooterDeserializerTest.java | 2 +-
.../maven/surefire/booter/ClasspathTest.java | 88 +-
.../maven/surefire/booter/CommandReaderTest.java | 57 +-
.../java/org/apache/maven/surefire/booter/Foo.java | 48 +-
.../surefire/booter/ForkedBooterMockTest.java | 232 +++-
.../surefire/booter/IsolatedClassLoaderTest.java | 66 ++
.../maven/surefire/booter/JUnit4SuiteTest.java | 7 +
.../surefire/booter/NewClassLoaderRunner.java | 0
.../surefire/booter/SurefireReflectorTest.java | 408 +++++++
.../spi/LegacyMasterProcessChannelDecoderTest.java | 243 ++++
.../spi/LegacyMasterProcessChannelEncoderTest.java | 223 ++--
surefire-extensions-api/pom.xml | 38 +-
.../surefire/extensions/CloseableDaemonThread.java | 17 +-
.../maven/surefire/extensions/CommandReader.java | 23 +-
.../maven/surefire/extensions/EventHandler.java | 12 +-
.../maven/surefire/extensions/ForkChannel.java | 108 ++
.../maven/surefire/extensions/ForkNodeFactory.java | 24 +-
.../surefire/extensions/StdOutStreamLine.java | 8 +-
.../extensions/util/LineConsumerThread.java | 21 +-
.../surefire/extensions/util/StreamFeeder.java | 89 --
.../extensions}/CommandlineExecutorTest.java | 27 +-
.../surefire/extensions}/JUnit4SuiteTest.java | 2 +-
surefire-extensions-spi/pom.xml | 42 +
.../spi/MasterProcessChannelProcessorFactory.java | 62 +
.../surefire/its/fixture/SurefireLauncher.java | 2 +
surefire-logger-api/pom.xml | 2 +-
.../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 +-
surefire-shadefire/pom.xml | 5 +
157 files changed, 7117 insertions(+), 4193 deletions(-)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 5340988..ccd2646 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -39,4 +39,4 @@ jobs:
java-version: 1.8
- name: Build with Maven
- run: mvn install -e -B -V -nsu --no-transfer-progress -P run-its
+ run: mvn install -e -B -V -nsu --no-transfer-progress -P run-its
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index 24b32c7..4b29517 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -21,10 +21,10 @@
properties(
[
- buildDiscarder(logRotator(artifactDaysToKeepStr: env.BRANCH_NAME == 'master' ? '1' : '2',
+ buildDiscarder(logRotator(artifactDaysToKeepStr: env.BRANCH_NAME == 'master' ? '14' : '7',
artifactNumToKeepStr: '50',
- daysToKeepStr: env.BRANCH_NAME == 'master' ? '10' : '5',
- numToKeepStr: env.BRANCH_NAME == 'master' ? '5' : '3')
+ daysToKeepStr: env.BRANCH_NAME == 'master' ? '30' : '14',
+ numToKeepStr: env.BRANCH_NAME == 'master' ? '20' : '10')
),
disableConcurrentBuilds()
]
@@ -213,6 +213,7 @@ static def sourcesPatternCsv() {
'**/surefire-api/src/main/java,' +
'**/surefire-booter/src/main/java,' +
'**/surefire-extensions-api/src/main/java,' +
+ '**/surefire-extensions-spi/src/main/java,' +
'**/surefire-grouper/src/main/java,' +
'**/surefire-its/src/main/java,' +
'**/surefire-logger-api/src/main/java,' +
@@ -229,6 +230,7 @@ static def classPatternCsv() {
'**/surefire-api/target/classes,' +
'**/surefire-booter/target/classes,' +
'**/surefire-extensions-api/target/classes,' +
+ '**/surefire-extensions-spi/target/classes,' +
'**/surefire-grouper/target/classes,' +
'**/surefire-its/target/classes,' +
'**/surefire-logger-api/target/classes,' +
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 a8c1927..7ba312a 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
@@ -25,6 +25,7 @@ import org.apache.maven.artifact.DefaultArtifact;
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.LegacyForkNodeFactory;
import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
@@ -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;
@@ -777,8 +779,6 @@ public abstract class AbstractSurefireMojo
@Component
private DependencyResolver dependencyResolver;
- private Artifact surefireBooterArtifact;
-
private Toolchain toolchain;
private int effectiveForkCount = -1;
@@ -835,6 +835,8 @@ public abstract class AbstractSurefireMojo
protected abstract String getEnableProcessChecker();
+ protected abstract ForkNodeFactory getForkNode();
+
/**
* This plugin MOJO artifact.
*
@@ -916,8 +918,7 @@ public abstract class AbstractSurefireMojo
getPluginName(), getDependencyResolver(),
getSession().isOffline() );
- surefireBooterArtifact = getBooterArtifact();
- if ( surefireBooterArtifact == null )
+ if ( getBooterArtifact() == null )
{
throw new RuntimeException( "Unable to locate surefire-booter in the list of plugin artifacts" );
}
@@ -1751,7 +1752,7 @@ public abstract class AbstractSurefireMojo
return new File( getBasedir(), ".surefire-" + configurationHash );
}
- private StartupConfiguration createStartupConfiguration( @Nonnull ProviderInfo provider, boolean isInprocess,
+ private StartupConfiguration createStartupConfiguration( @Nonnull ProviderInfo provider, boolean isForking,
@Nonnull ClassLoaderConfiguration classLoaderConfiguration,
@Nonnull DefaultScanResult scanResult,
@Nonnull Platform platform,
@@ -1762,7 +1763,7 @@ public abstract class AbstractSurefireMojo
{
Set<Artifact> providerArtifacts = provider.getProviderClasspath();
String providerName = provider.getProviderName();
- if ( canExecuteProviderWithModularPath( platform ) && !isInprocess )
+ if ( isForking && canExecuteProviderWithModularPath( platform ) )
{
String jvmExecutable = platform.getJdkExecAttributesForTests().getJvmExecutable();
String javaHome = Paths.get( jvmExecutable )
@@ -1804,8 +1805,8 @@ public abstract class AbstractSurefireMojo
getConsoleLogger().debug( testClasspath.getCompactLogMessage( "test(compact) classpath:" ) );
getConsoleLogger().debug( providerClasspath.getCompactLogMessage( "provider(compact) classpath:" ) );
- Artifact[] additionalInProcArtifacts =
- { getCommonArtifact(), getExtensionsArtifact(), getApiArtifact(), getLoggerApiArtifact() };
+ Artifact[] additionalInProcArtifacts = { getCommonArtifact(), getBooterArtifact(), getExtensionsArtifact(),
+ getApiArtifact(), getSpiArtifact(), getLoggerApiArtifact(), getSurefireSharedUtilsArtifact() };
Set<Artifact> inProcArtifacts = retainInProcArtifactsUnique( providerArtifacts, additionalInProcArtifacts );
Classpath inProcClasspath = createInProcClasspath( providerClasspath, inProcArtifacts );
getConsoleLogger().debug( inProcClasspath.getLogMessage( "in-process classpath:" ) );
@@ -1814,8 +1815,8 @@ public abstract class AbstractSurefireMojo
ClasspathConfiguration classpathConfiguration = new ClasspathConfiguration( testClasspath, providerClasspath,
inProcClasspath, effectiveIsEnableAssertions(), isChildDelegation() );
- return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration, isForking(),
- false, ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
+ return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
+ ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
}
private static Set<Artifact> retainInProcArtifactsUnique( Set<Artifact> providerArtifacts,
@@ -1907,8 +1908,8 @@ public abstract class AbstractSurefireMojo
ModularClasspath modularClasspath = new ModularClasspath( result.getMainModuleDescriptor().name(),
testModulepath.getClassPath(), packages, getTestClassesDirectory() );
- Artifact[] additionalInProcArtifacts =
- { getCommonArtifact(), getExtensionsArtifact(), getApiArtifact(), getLoggerApiArtifact() };
+ Artifact[] additionalInProcArtifacts = { getCommonArtifact(), getBooterArtifact(), getExtensionsArtifact(),
+ getApiArtifact(), getSpiArtifact(), getLoggerApiArtifact(), getSurefireSharedUtilsArtifact() };
Set<Artifact> inProcArtifacts = retainInProcArtifactsUnique( providerArtifacts, additionalInProcArtifacts );
Classpath inProcClasspath = createInProcClasspath( providerClasspath, inProcArtifacts );
@@ -1924,8 +1925,8 @@ public abstract class AbstractSurefireMojo
getConsoleLogger().debug( inProcClasspath.getLogMessage( "in-process classpath:" ) );
getConsoleLogger().debug( inProcClasspath.getCompactLogMessage( "in-process(compact) classpath:" ) );
- return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration, isForking(),
- false, ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
+ return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
+ ProcessCheckerType.toEnum( getEnableProcessChecker() ) );
}
private Artifact getCommonArtifact()
@@ -1938,11 +1939,21 @@ public abstract class AbstractSurefireMojo
return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-extensions-api" );
}
+ private Artifact getSpiArtifact()
+ {
+ return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-extensions-spi" );
+ }
+
private Artifact getApiArtifact()
{
return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-api" );
}
+ private Artifact getSurefireSharedUtilsArtifact()
+ {
+ return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-shared-utils" );
+ }
+
private Artifact getLoggerApiArtifact()
{
return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-logger-api" );
@@ -2232,7 +2243,7 @@ public abstract class AbstractSurefireMojo
@Nonnull TestClassPath testClasspathWrapper )
throws MojoExecutionException, MojoFailureException
{
- StartupConfiguration startupConfiguration = createStartupConfiguration( provider, false,
+ StartupConfiguration startupConfiguration = createStartupConfiguration( provider, true,
classLoaderConfiguration, scanResult, platform, testClasspathWrapper );
String configChecksum = getConfigChecksum();
StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum, true );
@@ -2249,7 +2260,7 @@ public abstract class AbstractSurefireMojo
@Nonnull TestClassPath testClasspathWrapper )
throws MojoExecutionException, MojoFailureException
{
- StartupConfiguration startupConfiguration = createStartupConfiguration( provider, true, classLoaderConfig,
+ StartupConfiguration startupConfiguration = createStartupConfiguration( provider, false, classLoaderConfig,
scanResult, platform, testClasspathWrapper );
String configChecksum = getConfigChecksum();
StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum, false );
@@ -2258,6 +2269,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 LegacyForkNodeFactory() : forkNode;
+ }
+
@Nonnull
private ForkConfiguration createForkConfiguration( Platform platform )
{
@@ -2265,7 +2284,11 @@ public abstract class AbstractSurefireMojo
Artifact shadeFire = getShadefireArtifact();
- Classpath bootClasspath = getArtifactClasspath( shadeFire != null ? shadeFire : surefireBooterArtifact );
+ Classpath bootClasspath = getArtifactClasspath( shadeFire != null ? shadeFire : getBooterArtifact() );
+
+ ForkNodeFactory forkNode = getForkNodeFactory();
+
+ getConsoleLogger().debug( "Found implementation of fork node factory: " + forkNode.getClass() );
if ( canExecuteProviderWithModularPath( platform ) )
{
@@ -2281,7 +2304,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
else if ( getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable() )
{
@@ -2297,7 +2321,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
else
{
@@ -2313,7 +2338,8 @@ public abstract class AbstractSurefireMojo
getEffectiveForkCount(),
reuseForks,
platform,
- getConsoleLogger() );
+ getConsoleLogger(),
+ forkNode );
}
}
@@ -2924,7 +2950,7 @@ public abstract class AbstractSurefireMojo
{
// add the JUnit provider as default - it doesn't require JUnit to be present,
// since it supports POJO tests.
- String version = surefireBooterArtifact.getBaseVersion();
+ String version = getBooterArtifact().getBaseVersion();
return surefireDependencyResolver.getProviderClasspath( "surefire-junit3", version );
}
}
@@ -2963,7 +2989,7 @@ public abstract class AbstractSurefireMojo
@Nonnull
public Set<Artifact> getProviderClasspath()
{
- String version = surefireBooterArtifact.getBaseVersion();
+ String version = getBooterArtifact().getBaseVersion();
return surefireDependencyResolver.getProviderClasspath( "surefire-junit4", version );
}
}
@@ -3006,7 +3032,7 @@ public abstract class AbstractSurefireMojo
@Nonnull
public Set<Artifact> getProviderClasspath() throws MojoExecutionException
{
- String surefireVersion = surefireBooterArtifact.getBaseVersion();
+ String surefireVersion = getBooterArtifact().getBaseVersion();
Map<String, Artifact> providerArtifacts =
surefireDependencyResolver.getProviderClasspathAsMap( "surefire-junit-platform", surefireVersion );
Map<String, Artifact> testDependencies = testClasspath.getTestDependencies();
@@ -3177,7 +3203,7 @@ public abstract class AbstractSurefireMojo
@Nonnull
public Set<Artifact> getProviderClasspath()
{
- String version = surefireBooterArtifact.getBaseVersion();
+ String version = getBooterArtifact().getBaseVersion();
return surefireDependencyResolver.getProviderClasspath( "surefire-junit47", version );
}
}
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/SurefireDependencyResolver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
index 4684563..6da4a1a 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
@@ -74,6 +74,7 @@ final class SurefireDependencyResolver
"surefire-junit-platform",
"surefire-api",
"surefire-logger-api",
+ "surefire-shared-utils",
"common-java5",
"common-junit3",
"common-junit4",
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..f8e08ea 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,12 @@ 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..9a04326 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.setNullableProperty( 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..9c906c4 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,12 @@ 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..a41384a 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;
@@ -33,12 +33,6 @@ import org.apache.maven.plugin.surefire.booterclient.output.NativeStdErrStreamCo
import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.extensions.util.CommandlineExecutor;
-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 +41,14 @@ 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.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
+import org.apache.maven.surefire.extensions.util.CommandlineExecutor;
+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.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.suite.RunResult;
@@ -72,14 +74,12 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
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;
@@ -88,12 +88,11 @@ import static org.apache.maven.plugin.surefire.SurefireHelper.DUMP_FILE_PREFIX;
import static org.apache.maven.plugin.surefire.SurefireHelper.replaceForkThreadsInPath;
import static org.apache.maven.plugin.surefire.booterclient.ForkNumberBucket.drawNumber;
import static org.apache.maven.plugin.surefire.booterclient.ForkNumberBucket.returnNumber;
-import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream
- .TestLessInputStreamBuilder;
-import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
-import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.removeShutdownHook;
+import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
import static org.apache.maven.surefire.booter.SystemPropertyManager.writePropertiesFile;
import static org.apache.maven.surefire.cli.CommandLineOption.SHOW_ERRORS;
+import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
+import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.removeShutdownHook;
import static org.apache.maven.surefire.suite.RunResult.SUCCESS;
import static org.apache.maven.surefire.suite.RunResult.failure;
import static org.apache.maven.surefire.suite.RunResult.timeout;
@@ -192,7 +191,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 +211,17 @@ public class ForkStarter
@Override
public void close()
{
- run();
- testProvidingInputStream.clear();
- if ( inputStreamCloserHook != null )
+ try
{
- removeShutdownHook( inputStreamCloserHook );
+ run();
+ }
+ finally
+ {
+ testProvidingInputStream.clear();
+ if ( inputStreamCloserHook != null )
+ {
+ removeShutdownHook( inputStreamCloserHook );
+ }
}
}
@@ -287,9 +292,9 @@ public class ForkStarter
DefaultReporterFactory forkedReporterFactory =
new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
defaultReporterFactories.add( forkedReporterFactory );
- ForkClient forkClient =
- new ForkClient( forkedReporterFactory, stream, log, new AtomicBoolean(), forkNumber );
- return fork( null, props, forkClient, effectiveSystemProperties, forkNumber, stream, false );
+ ForkClient forkClient = new ForkClient( forkedReporterFactory, stream, forkNumber );
+ return fork( null, props, forkClient, effectiveSystemProperties, forkNumber, stream,
+ forkConfiguration.getForkNodeFactory(), false );
}
finally
{
@@ -350,7 +355,6 @@ public class ForkStarter
int failFastCount = providerConfiguration.getSkipAfterFailureCount();
final AtomicInteger notifyStreamsToSkipTestsJustNow = new AtomicInteger( failFastCount );
final Collection<Future<RunResult>> results = new ArrayList<>( forkCount );
- final AtomicBoolean printedErrorStream = new AtomicBoolean();
for ( final TestProvidingInputStream testProvidingInputStream : testStreams )
{
Callable<RunResult> pf = new Callable<RunResult>()
@@ -363,8 +367,7 @@ public class ForkStarter
DefaultReporterFactory reporter =
new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
defaultReporterFactories.add( reporter );
- ForkClient forkClient = new ForkClient( reporter, testProvidingInputStream, log,
- printedErrorStream, forkNumber )
+ ForkClient forkClient = new ForkClient( reporter, testProvidingInputStream, forkNumber )
{
@Override
protected void stopOnNextTest()
@@ -379,7 +382,8 @@ public class ForkStarter
try
{
return fork( null, new PropertiesWrapper( providerProperties ), forkClient,
- effectiveSystemProperties, forkNumber, testProvidingInputStream, true );
+ effectiveSystemProperties, forkNumber, testProvidingInputStream,
+ forkConfiguration.getForkNodeFactory(), true );
}
finally
{
@@ -423,7 +427,6 @@ public class ForkStarter
addShutDownHook( shutdown );
int failFastCount = providerConfiguration.getSkipAfterFailureCount();
final AtomicInteger notifyStreamsToSkipTestsJustNow = new AtomicInteger( failFastCount );
- final AtomicBoolean printedErrorStream = new AtomicBoolean();
for ( final Object testSet : getSuitesIterator() )
{
Callable<RunResult> pf = new Callable<RunResult>()
@@ -437,8 +440,7 @@ public class ForkStarter
new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
defaultReporterFactories.add( forkedReporterFactory );
TestLessInputStream stream = builder.build();
- ForkClient forkClient = new ForkClient( forkedReporterFactory, stream,
- log, printedErrorStream, forkNumber )
+ ForkClient forkClient = new ForkClient( forkedReporterFactory, stream, forkNumber )
{
@Override
protected void stopOnNextTest()
@@ -453,7 +455,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 +552,28 @@ 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
{
+ CloseableCloser closer = new CloseableCloser( forkNumber, commandReader );
final String tempDir;
final File surefireProperties;
final File systPropsFile;
+ final ForkChannel forkChannel;
try
{
+ forkChannel = forkNodeFactory.createForkChannel( forkNumber, log );
+ closer.addCloseable( forkChannel );
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
+ + "' for the implementation " + forkChannel.getClass() );
+ surefireProperties = booterSerializer.serialize( providerProperties, providerConfiguration,
+ startupConfiguration, testSet, readTestsFromInStream, pluginPid, forkNumber, connectionString );
if ( effectiveSystemProperties != null )
{
@@ -588,10 +598,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,38 +609,40 @@ public class ForkStarter
}
ThreadedStreamConsumer eventConsumer = new ThreadedStreamConsumer( forkClient );
- CloseableCloser closer = new CloseableCloser( forkNumber, eventConsumer, requireNonNull( commandInputStream ) );
+ closer.addCloseable( eventConsumer );
log.debug( "Forking command line: " + cli );
Integer result = null;
RunResult runResult = null;
SurefireBooterForkException booterForkException = null;
- StreamFeeder in = null;
- LineConsumerThread out = null;
- LineConsumerThread err = null;
+ CloseableDaemonThread in = null;
+ CloseableDaemonThread out = null;
+ CloseableDaemonThread err = null;
DefaultReporterFactory reporter = forkClient.getDefaultReporterFactory();
currentForkClients.add( forkClient );
- CountdownCloseable countdownCloseable = new CountdownCloseable( eventConsumer, 2 );
+ CountdownCloseable countdownCloseable =
+ new CountdownCloseable( eventConsumer, 1 + ( forkChannel.useStdOut() ? 1 : 0 ) );
try ( CommandlineExecutor exec = new CommandlineExecutor( cli, countdownCloseable ) )
{
- // default impl of the extension - solves everything including the encoder/decoder, Process starter,
- // adaptation of the streams to pipes and sockets
- // non-default impl may use another classes and not the LineConsumerThread, StreamFeeder - freedom
- // 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 );
+
+ forkChannel.connectToClient();
+ log.debug( "Fork Channel [" + forkNumber + "] connected to the client." );
+
+ in = forkChannel.bindCommandReader( commandReader, streams.getStdInChannel() );
in.start();
- out = new LineConsumerThread( "std-out-fork-" + forkNumber, streams.getStdOutChannel(),
- eventConsumer, countdownCloseable );
+
+ out = forkChannel.bindEventHandler( eventConsumer, countdownCloseable, streams.getStdOutChannel() );
out.start();
- NativeStdErrStreamConsumer stdErrConsumer = new NativeStdErrStreamConsumer( reporter );
- err = new LineConsumerThread( "std-err-fork-" + forkNumber, streams.getStdErrChannel(),
- stdErrConsumer, countdownCloseable );
+
+ EventHandler<String> stdErrConsumer = new NativeStdErrStreamConsumer( reporter );
+ err = new LineConsumerThread( "fork-" + forkNumber + "-err-thread-", streams.getStdErrChannel(),
+ stdErrConsumer, countdownCloseable );
err.start();
+
result = exec.awaitExit();
- // END: end of the call of the extension
if ( forkClient.hadTimeout() )
{
@@ -647,13 +656,15 @@ public class ForkStarter
}
catch ( InterruptedException e )
{
+ log.error( "Closing the streams after (InterruptedException) '" + e.getLocalizedMessage() + "'" );
// maybe implement it in the Future.cancel() of the extension or similar
in.disable();
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();
@@ -662,10 +673,12 @@ public class ForkStarter
}
finally
{
+ log.debug( "Closing the fork " + forkNumber + " after "
+ + ( forkClient.isSaidGoodBye() ? "saying GoodBye." : "not saying Good Bye." ) );
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() )
{
@@ -729,7 +742,6 @@ public class ForkStarter
if ( booterForkException != null )
{
- // noinspection ThrowFromFinallyBlock
throw booterForkException;
}
}
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..382bec6 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,12 @@ 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..d659a6c 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,12 @@ 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/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefferedChannelCommandSender.java
similarity index 67%
rename from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.java
rename to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DefferedChannelCommandSender.java
index 8faa803..e489caa 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.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.plugin.surefire.booterclient.output;
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,11 +19,17 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* under the License.
*/
+import java.io.Closeable;
+
/**
+ * 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 3.0.0-M4
*/
-public interface ForkedChannelDecoderErrorHandler
+public interface DefferedChannelCommandSender
+ extends NotifiableTestStream, Closeable
{
- void handledError( String line, Throwable e );
+ 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/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
index 18cfe28..b4de014 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -22,7 +22,9 @@ package org.apache.maven.plugin.surefire.booterclient.output;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
@@ -30,25 +32,20 @@ import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.report.TestSetReportEntry;
-import java.io.BufferedReader;
+import javax.annotation.Nonnull;
import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import static java.lang.System.currentTimeMillis;
import static java.util.Collections.unmodifiableMap;
import static org.apache.maven.surefire.booter.Shutdown.KILL;
import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
-import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
-import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
// todo move to the same package with ForkStarter
@@ -58,9 +55,8 @@ import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
* @author Kristian Rosenvold
*/
public class ForkClient
- implements StreamConsumer
+ implements EventHandler<Event>
{
- private static final String PRINTABLE_JVM_NATIVE_STREAM = "Listening for transport dt_socket at address:";
private static final long START_TIME_ZERO = 0L;
private static final long START_TIME_NEGATIVE_TIMEOUT = -1L;
@@ -74,26 +70,14 @@ public class ForkClient
/**
* <em>testSetStartedAt</em> is set to non-zero after received
- * {@link org.apache.maven.surefire.booter.ForkedChannelEncoder#testSetStarting(ReportEntry, boolean)}.
+ * {@link MasterProcessChannelEncoder#testSetStarting(ReportEntry, boolean)}.
*/
private final AtomicLong testSetStartedAt = new AtomicLong( START_TIME_ZERO );
- private final ForkedChannelDecoder decoder = new ForkedChannelDecoder();
-
- private final ConsoleLogger log;
-
- /**
- * prevents from printing same warning
- */
- private final AtomicBoolean printedErrorStream;
+ private final ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
private final int forkNumber;
- /**
- * Used by single Thread started by {@link ThreadedStreamConsumer} and therefore does not need to be volatile.
- */
- private final ForkedChannelDecoderErrorHandler errorHandler;
-
private RunListener testSetReporter;
/**
@@ -104,41 +88,29 @@ public class ForkClient
private volatile StackTraceWriter errorInFork;
public ForkClient( DefaultReporterFactory defaultReporterFactory, NotifiableTestStream notifiableTestStream,
- ConsoleLogger log, AtomicBoolean printedErrorStream, int forkNumber )
+ int forkNumber )
{
this.defaultReporterFactory = defaultReporterFactory;
this.notifiableTestStream = notifiableTestStream;
- this.log = log;
- this.printedErrorStream = printedErrorStream;
this.forkNumber = forkNumber;
- decoder.setTestSetStartingListener( new TestSetStartingListener() );
- decoder.setTestSetCompletedListener( new TestSetCompletedListener() );
- decoder.setTestStartingListener( new TestStartingListener() );
- decoder.setTestSucceededListener( new TestSucceededListener() );
- decoder.setTestFailedListener( new TestFailedListener() );
- decoder.setTestSkippedListener( new TestSkippedListener() );
- decoder.setTestErrorListener( new TestErrorListener() );
- decoder.setTestAssumptionFailureListener( new TestAssumptionFailureListener() );
- decoder.setSystemPropertiesListener( new SystemPropertiesListener() );
- decoder.setStdOutListener( new StdOutListener() );
- decoder.setStdErrListener( new StdErrListener() );
- decoder.setConsoleInfoListener( new ConsoleListener() );
- decoder.setAcquireNextTestListener( new AcquireNextTestListener() );
- decoder.setConsoleErrorListener( new ErrorListener() );
- decoder.setByeListener( new ByeListener() );
- decoder.setStopOnNextTestListener( new StopOnNextTestListener() );
- decoder.setConsoleDebugListener( new DebugListener() );
- decoder.setConsoleWarningListener( new WarningListener() );
- errorHandler = new ErrorHandler();
- }
-
- private final class ErrorHandler implements ForkedChannelDecoderErrorHandler
- {
- @Override
- public void handledError( String line, Throwable e )
- {
- logStreamWarning( line, e );
- }
+ notifier.setTestSetStartingListener( new TestSetStartingListener() );
+ notifier.setTestSetCompletedListener( new TestSetCompletedListener() );
+ notifier.setTestStartingListener( new TestStartingListener() );
+ notifier.setTestSucceededListener( new TestSucceededListener() );
+ notifier.setTestFailedListener( new TestFailedListener() );
+ notifier.setTestSkippedListener( new TestSkippedListener() );
+ notifier.setTestErrorListener( new TestErrorListener() );
+ notifier.setTestAssumptionFailureListener( new TestAssumptionFailureListener() );
+ notifier.setSystemPropertiesListener( new SystemPropertiesListener() );
+ notifier.setStdOutListener( new StdOutListener() );
+ notifier.setStdErrListener( new StdErrListener() );
+ notifier.setConsoleInfoListener( new ConsoleListener() );
+ notifier.setAcquireNextTestListener( new AcquireNextTestListener() );
+ notifier.setConsoleErrorListener( new ErrorListener() );
+ notifier.setByeListener( new ByeListener() );
+ notifier.setStopOnNextTestListener( new StopOnNextTestListener() );
+ notifier.setConsoleDebugListener( new DebugListener() );
+ notifier.setConsoleWarningListener( new WarningListener() );
}
private final class TestSetStartingListener
@@ -167,7 +139,7 @@ public class ForkClient
}
}
- private final class TestStartingListener implements ForkedProcessReportEventListener
+ private final class TestStartingListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -177,7 +149,7 @@ public class ForkClient
}
}
- private final class TestSucceededListener implements ForkedProcessReportEventListener
+ private final class TestSucceededListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -187,7 +159,7 @@ public class ForkClient
}
}
- private final class TestFailedListener implements ForkedProcessReportEventListener
+ private final class TestFailedListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -197,7 +169,7 @@ public class ForkClient
}
}
- private final class TestSkippedListener implements ForkedProcessReportEventListener
+ private final class TestSkippedListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -207,7 +179,7 @@ public class ForkClient
}
}
- private final class TestErrorListener implements ForkedProcessReportEventListener
+ private final class TestErrorListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -217,7 +189,7 @@ public class ForkClient
}
}
- private final class TestAssumptionFailureListener implements ForkedProcessReportEventListener
+ private final class TestAssumptionFailureListener implements ForkedProcessReportEventListener<ReportEntry>
{
@Override
public void handle( RunMode runMode, ReportEntry reportEntry )
@@ -276,18 +248,19 @@ public class ForkClient
private class ErrorListener implements ForkedProcessStackTraceEventListener
{
@Override
- public void handle( String msg, String smartStackTrace, String stackTrace )
+ public void handle( @Nonnull StackTraceWriter stackTrace )
{
+ String msg = stackTrace.getThrowable().getMessage();
if ( errorInFork == null )
{
- errorInFork = deserializeStackTraceWriter( msg, smartStackTrace, stackTrace );
+ errorInFork = stackTrace.writeTraceToString() != null ? stackTrace : null;
if ( msg != null )
{
getOrCreateConsoleLogger()
.error( msg );
}
}
- dumpToLoFile( msg, null );
+ dumpToLoFile( msg );
}
}
@@ -372,12 +345,9 @@ public class ForkClient
}
@Override
- public final void consumeLine( String s )
+ public final void handleEvent( @Nonnull Event event )
{
- if ( isNotBlank( s ) )
- {
- processLine( s );
- }
+ notifier.notifyEvent( event );
}
private void setCurrentStartTime()
@@ -404,53 +374,11 @@ public class ForkClient
return testSetReporter;
}
- private void processLine( String event )
- {
- decoder.handleEvent( event, errorHandler );
- }
-
- private File dumpToLoFile( String msg, Throwable e )
+ void dumpToLoFile( String msg )
{
File reportsDir = defaultReporterFactory.getReportsDirectory();
InPluginProcessDumpSingleton util = InPluginProcessDumpSingleton.getSingleton();
- return e == null
- ? util.dumpStreamText( msg, reportsDir, forkNumber )
- : util.dumpStreamException( e, msg, reportsDir, forkNumber );
- }
-
- private void logStreamWarning( String event, Throwable e )
- {
- if ( event == null || !event.contains( PRINTABLE_JVM_NATIVE_STREAM ) )
- {
- String msg = "Corrupted STDOUT by directly writing to native stream in forked JVM " + forkNumber + ".";
- File dump = dumpToLoFile( msg + " Stream '" + event + "'.", e );
-
- if ( printedErrorStream.compareAndSet( false, true ) )
- {
- log.warning( msg + " See FAQ web page and the dump file " + dump.getAbsolutePath() );
- }
-
- if ( log.isDebugEnabled() && event != null )
- {
- log.debug( event );
- }
- }
- else
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( event );
- }
- else if ( log.isInfoEnabled() )
- {
- log.info( event );
- }
- else
- {
- // In case of debugging forked JVM, see PRINTABLE_JVM_NATIVE_STREAM.
- System.out.println( event );
- }
- }
+ util.dumpStreamText( msg, reportsDir, forkNumber );
}
private void writeTestOutput( String output, boolean newLine, boolean isStdout )
@@ -459,23 +387,6 @@ public class ForkClient
.writeTestOutput( output, newLine, isStdout );
}
- public final void consumeMultiLineContent( String s )
- throws IOException
- {
- if ( isBlank( s ) )
- {
- logStreamWarning( s, null );
- }
- else
- {
- BufferedReader stringReader = new BufferedReader( new StringReader( s ) );
- for ( String s1 = stringReader.readLine(); s1 != null; s1 = stringReader.readLine() )
- {
- consumeLine( s1 );
- }
- }
- }
-
public final Map<String, String> getTestVmSystemProperties()
{
return unmodifiableMap( testVmSystemProperties );
@@ -531,11 +442,4 @@ public class ForkClient
{
return !testsInProgress.isEmpty();
}
-
- private StackTraceWriter deserializeStackTraceWriter( String stackTraceMessage,
- String smartStackTrace, String stackTrace )
- {
- boolean hasTrace = stackTrace != null;
- return hasTrace ? new DeserializedStacktraceWriter( stackTraceMessage, smartStackTrace, stackTrace ) : null;
- }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java
deleted file mode 100644
index 0c049d6..0000000
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java
+++ /dev/null
@@ -1,352 +0,0 @@
-package org.apache.maven.plugin.surefire.booterclient.output;
-
-/*
- * 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.commons.codec.binary.Base64;
-import org.apache.maven.surefire.booter.ForkedProcessEvent;
-import org.apache.maven.surefire.report.ReportEntry;
-import org.apache.maven.surefire.report.RunMode;
-import org.apache.maven.surefire.report.StackTraceWriter;
-
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.MAGIC_NUMBER;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDERR;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDERR_NEW_LINE;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDOUT;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDOUT_NEW_LINE;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_BYE;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_DEBUG;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_INFO;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_WARNING;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_NEXT_TEST;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STOP_ON_NEXT_TEST;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ERROR;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_FAILED;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SKIPPED;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_STARTING;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SUCCEEDED;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_COMPLETED;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_STARTING;
-import static org.apache.maven.surefire.booter.ForkedProcessEvent.EVENTS;
-import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
-import static org.apache.maven.surefire.report.RunMode.MODES;
-import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
-import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
-import static java.util.Objects.requireNonNull;
-
-/**
- * magic number : run mode : opcode [: opcode specific data]*
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M4
- */
-public final class ForkedChannelDecoder
-{
- private static final Base64 BASE64 = new Base64();
-
- private volatile ForkedProcessPropertyEventListener propertyEventListener;
- private volatile ForkedProcessStackTraceEventListener consoleErrorEventListener;
- private volatile ForkedProcessExitErrorListener exitErrorEventListener;
-
- private final ConcurrentMap<ForkedProcessEvent, ForkedProcessReportEventListener<?>> reportEventListeners =
- new ConcurrentHashMap<>();
-
- private final ConcurrentMap<ForkedProcessEvent, ForkedProcessStandardOutErrEventListener> stdOutErrEventListeners =
- new ConcurrentHashMap<>();
-
- private final ConcurrentMap<ForkedProcessEvent, ForkedProcessStringEventListener> consoleEventListeners =
- new ConcurrentHashMap<>();
-
- private final ConcurrentMap<ForkedProcessEvent, ForkedProcessEventListener> controlEventListeners =
- new ConcurrentHashMap<>();
-
- public void setSystemPropertiesListener( ForkedProcessPropertyEventListener listener )
- {
- propertyEventListener = requireNonNull( listener );
- }
-
- public <T extends ReportEntry> void setTestSetStartingListener( ForkedProcessReportEventListener<T> listener )
- {
- reportEventListeners.put( BOOTERCODE_TESTSET_STARTING, requireNonNull( listener ) );
- }
-
- public void setTestSetCompletedListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TESTSET_COMPLETED, requireNonNull( listener ) );
- }
-
- public void setTestStartingListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_STARTING, requireNonNull( listener ) );
- }
-
- public void setTestSucceededListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_SUCCEEDED, requireNonNull( listener ) );
- }
-
- public void setTestFailedListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_FAILED, requireNonNull( listener ) );
- }
-
- public void setTestSkippedListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_SKIPPED, requireNonNull( listener ) );
- }
-
- public void setTestErrorListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_ERROR, requireNonNull( listener ) );
- }
-
- public void setTestAssumptionFailureListener( ForkedProcessReportEventListener<?> listener )
- {
- reportEventListeners.put( BOOTERCODE_TEST_ASSUMPTIONFAILURE, requireNonNull( listener ) );
- }
-
- public void setStdOutListener( ForkedProcessStandardOutErrEventListener listener )
- {
- stdOutErrEventListeners.put( BOOTERCODE_STDOUT, requireNonNull( listener ) );
- stdOutErrEventListeners.put( BOOTERCODE_STDOUT_NEW_LINE, requireNonNull( listener ) );
- }
-
- public void setStdErrListener( ForkedProcessStandardOutErrEventListener listener )
- {
- stdOutErrEventListeners.put( BOOTERCODE_STDERR, requireNonNull( listener ) );
- stdOutErrEventListeners.put( BOOTERCODE_STDERR_NEW_LINE, requireNonNull( listener ) );
- }
-
- public void setConsoleInfoListener( ForkedProcessStringEventListener listener )
- {
- consoleEventListeners.put( BOOTERCODE_CONSOLE_INFO, requireNonNull( listener ) );
- }
-
- public void setConsoleErrorListener( ForkedProcessStackTraceEventListener listener )
- {
- consoleErrorEventListener = requireNonNull( listener );
- }
-
- public void setConsoleDebugListener( ForkedProcessStringEventListener listener )
- {
- consoleEventListeners.put( BOOTERCODE_CONSOLE_DEBUG, requireNonNull( listener ) );
- }
-
- public void setConsoleWarningListener( ForkedProcessStringEventListener listener )
- {
- consoleEventListeners.put( BOOTERCODE_CONSOLE_WARNING, requireNonNull( listener ) );
- }
-
- public void setByeListener( ForkedProcessEventListener listener )
- {
- controlEventListeners.put( BOOTERCODE_BYE, requireNonNull( listener ) );
- }
-
- public void setStopOnNextTestListener( ForkedProcessEventListener listener )
- {
- controlEventListeners.put( BOOTERCODE_STOP_ON_NEXT_TEST, requireNonNull( listener ) );
- }
-
- public void setAcquireNextTestListener( ForkedProcessEventListener listener )
- {
- controlEventListeners.put( BOOTERCODE_NEXT_TEST, requireNonNull( listener ) );
- }
-
- public void setExitErrorEventListener( ForkedProcessExitErrorListener listener )
- {
- exitErrorEventListener = requireNonNull( listener );
- }
-
- public void handleEvent( String line, ForkedChannelDecoderErrorHandler errorHandler )
- {
- if ( line == null || !line.startsWith( MAGIC_NUMBER ) )
- {
- errorHandler.handledError( line, null );
- return;
- }
-
- String[] tokens = line.substring( MAGIC_NUMBER.length() ).split( ":" );
- int index = -1;
- String opcode = tokens.length > ++index ? tokens[index] : null;
- ForkedProcessEvent event = opcode == null ? null : EVENTS.get( opcode );
- if ( event == null )
- {
- errorHandler.handledError( line, null );
- return;
- }
-
- try
- {
- if ( event.isControlCategory() )
- {
- ForkedProcessEventListener listener = controlEventListeners.get( event );
- if ( listener != null )
- {
- listener.handle();
- }
- }
- else if ( event.isConsoleCategory() )
- {
- ForkedProcessStringEventListener listener = consoleEventListeners.get( event );
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- if ( listener != null && encoding != null )
- {
- String msg = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- listener.handle( msg );
- }
- }
- else if ( event.isConsoleErrorCategory() )
- {
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- if ( consoleErrorEventListener != null && encoding != null )
- {
- String msg = tokens.length > ++index ? decode( tokens[index], encoding ) : null;
- String smartStackTrace =
- tokens.length > ++index ? decode( tokens[index], encoding ) : null;
- String stackTrace = tokens.length > ++index ? decode( tokens[index], encoding ) : null;
- consoleErrorEventListener.handle( msg, smartStackTrace, stackTrace );
- }
- }
- else if ( event.isStandardStreamCategory() )
- {
- ForkedProcessStandardOutErrEventListener listener = stdOutErrEventListeners.get( event );
- RunMode mode = tokens.length > ++index ? MODES.get( tokens[index] ) : null;
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- if ( listener != null && encoding != null && mode != null )
- {
- boolean newLine = event == BOOTERCODE_STDOUT_NEW_LINE || event == BOOTERCODE_STDERR_NEW_LINE;
- String output = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- listener.handle( mode, output, newLine );
- }
- }
- else if ( event.isSysPropCategory() )
- {
- RunMode mode = tokens.length > ++index ? MODES.get( tokens[index] ) : null;
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- String key = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- if ( propertyEventListener != null && isNotBlank( key ) )
- {
- String value = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- propertyEventListener.handle( mode, key, value );
- }
- }
- else if ( event.isTestCategory() )
- {
- ForkedProcessReportEventListener listener = reportEventListeners.get( event );
- RunMode mode = tokens.length > ++index ? MODES.get( tokens[index] ) : null;
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- if ( listener != null && encoding != null && mode != null )
- {
- String sourceName = tokens.length > ++index ? tokens[index] : null;
- String sourceText = tokens.length > ++index ? tokens[index] : null;
- String name = tokens.length > ++index ? tokens[index] : null;
- String nameText = tokens.length > ++index ? tokens[index] : null;
- String group = tokens.length > ++index ? tokens[index] : null;
- String message = tokens.length > ++index ? tokens[index] : null;
- String elapsed = tokens.length > ++index ? tokens[index] : null;
- String traceMessage = tokens.length > ++index ? tokens[index] : null;
- String smartTrimmedStackTrace = tokens.length > ++index ? tokens[index] : null;
- String stackTrace = tokens.length > ++index ? tokens[index] : null;
- ReportEntry reportEntry = toReportEntry( encoding, sourceName, sourceText, name, nameText,
- group, message, elapsed, traceMessage, smartTrimmedStackTrace, stackTrace );
- listener.handle( mode, reportEntry );
- }
- }
- else if ( event.isJvmExitError() )
- {
- if ( exitErrorEventListener != null )
- {
- Charset encoding = tokens.length > ++index ? Charset.forName( tokens[index] ) : null;
- String message = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- String smartTrimmedStackTrace =
- tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- String stackTrace = tokens.length > ++index ? decode( tokens[index], encoding ) : "";
- exitErrorEventListener.handle( message, smartTrimmedStackTrace, stackTrace );
- }
- }
- }
- catch ( IllegalArgumentException e )
- {
- errorHandler.handledError( line, e );
- }
- }
-
- static ReportEntry toReportEntry( Charset encoding,
- // ReportEntry:
- String encSource, String encSourceText, String encName, String encNameText,
- String encGroup, String encMessage, String encTimeElapsed,
- // StackTraceWriter:
- String encTraceMessage, String encSmartTrimmedStackTrace, String encStackTrace )
- throws NumberFormatException
- {
- if ( encoding == null )
- {
- // corrupted or incomplete stream
- return null;
- }
-
- String source = decode( encSource, encoding );
- String sourceText = decode( encSourceText, encoding );
- String name = decode( encName, encoding );
- String nameText = decode( encNameText, encoding );
- String group = decode( encGroup, encoding );
- StackTraceWriter stackTraceWriter =
- decodeTrace( encoding, encTraceMessage, encSmartTrimmedStackTrace, encStackTrace );
- Integer elapsed = decodeToInteger( encTimeElapsed );
- String message = decode( encMessage, encoding );
- return reportEntry( source, sourceText, name, nameText,
- group, stackTraceWriter, elapsed, message, Collections.<String, String>emptyMap() );
- }
-
- static String decode( String line, Charset encoding )
- {
- // ForkedChannelEncoder is encoding the stream with US_ASCII
- return line == null || "-".equals( line )
- ? null
- : new String( BASE64.decode( line.getBytes( US_ASCII ) ), encoding );
- }
-
- static Integer decodeToInteger( String line )
- {
- return line == null || "-".equals( line ) ? null : Integer.decode( line );
- }
-
- private static StackTraceWriter decodeTrace( Charset encoding, String encTraceMessage,
- String encSmartTrimmedStackTrace, String encStackTrace )
- {
- if ( isBlank( encStackTrace ) || "-".equals( encStackTrace ) )
- {
- return null;
- }
- else
- {
- String traceMessage = decode( encTraceMessage, encoding );
- String stackTrace = decode( encStackTrace, encoding );
- String smartTrimmedStackTrace = decode( encSmartTrimmedStackTrace, encoding );
- return new DeserializedStacktraceWriter( traceMessage, smartTrimmedStackTrace, stackTrace );
- }
- }
-}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java
new file mode 100644
index 0000000..58f9344
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java
@@ -0,0 +1,248 @@
+package org.apache.maven.plugin.surefire.booterclient.output;
+
+/*
+ * 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.ForkedProcessEventType;
+import org.apache.maven.surefire.eventapi.AbstractConsoleEvent;
+import org.apache.maven.surefire.eventapi.AbstractStandardStreamEvent;
+import org.apache.maven.surefire.eventapi.AbstractTestControlEvent;
+import org.apache.maven.surefire.eventapi.ConsoleErrorEvent;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.eventapi.JvmExitErrorEvent;
+import org.apache.maven.surefire.eventapi.SystemPropertyEvent;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static java.util.Objects.requireNonNull;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
+
+/**
+ * magic number : run mode : opcode [: opcode specific data]*
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+public final class ForkedProcessEventNotifier
+{
+ private volatile ForkedProcessPropertyEventListener propertyEventListener;
+ private volatile ForkedProcessStackTraceEventListener consoleErrorEventListener;
+ private volatile ForkedProcessExitErrorListener exitErrorEventListener;
+
+ private final ConcurrentMap<ForkedProcessEventType, ForkedProcessReportEventListener<?>> reportEventListeners =
+ new ConcurrentHashMap<>();
+
+ private final ConcurrentMap<ForkedProcessEventType, ForkedProcessStandardOutErrEventListener>
+ stdOutErrEventListeners = new ConcurrentHashMap<>();
+
+ private final ConcurrentMap<ForkedProcessEventType, ForkedProcessStringEventListener> consoleEventListeners =
+ new ConcurrentHashMap<>();
+
+ private final ConcurrentMap<ForkedProcessEventType, ForkedProcessEventListener> controlEventListeners =
+ new ConcurrentHashMap<>();
+
+ public void setSystemPropertiesListener( ForkedProcessPropertyEventListener listener )
+ {
+ propertyEventListener = requireNonNull( listener );
+ }
+
+ public <T extends ReportEntry> void setTestSetStartingListener( ForkedProcessReportEventListener<T> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TESTSET_STARTING, requireNonNull( listener ) );
+ }
+
+ public void setTestSetCompletedListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TESTSET_COMPLETED, requireNonNull( listener ) );
+ }
+
+ public void setTestStartingListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_STARTING, requireNonNull( listener ) );
+ }
+
+ public void setTestSucceededListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_SUCCEEDED, requireNonNull( listener ) );
+ }
+
+ public void setTestFailedListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_FAILED, requireNonNull( listener ) );
+ }
+
+ public void setTestSkippedListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_SKIPPED, requireNonNull( listener ) );
+ }
+
+ public void setTestErrorListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_ERROR, requireNonNull( listener ) );
+ }
+
+ public void setTestAssumptionFailureListener( ForkedProcessReportEventListener<?> listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_ASSUMPTIONFAILURE, requireNonNull( listener ) );
+ }
+
+ public void setStdOutListener( ForkedProcessStandardOutErrEventListener listener )
+ {
+ stdOutErrEventListeners.put( BOOTERCODE_STDOUT, requireNonNull( listener ) );
+ stdOutErrEventListeners.put( BOOTERCODE_STDOUT_NEW_LINE, requireNonNull( listener ) );
+ }
+
+ public void setStdErrListener( ForkedProcessStandardOutErrEventListener listener )
+ {
+ stdOutErrEventListeners.put( BOOTERCODE_STDERR, requireNonNull( listener ) );
+ stdOutErrEventListeners.put( BOOTERCODE_STDERR_NEW_LINE, requireNonNull( listener ) );
+ }
+
+ public void setConsoleInfoListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_INFO, requireNonNull( listener ) );
+ }
+
+ public void setConsoleErrorListener( ForkedProcessStackTraceEventListener listener )
+ {
+ consoleErrorEventListener = requireNonNull( listener );
+ }
+
+ public void setConsoleDebugListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_DEBUG, requireNonNull( listener ) );
+ }
+
+ public void setConsoleWarningListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_WARNING, requireNonNull( listener ) );
+ }
+
+ public void setByeListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_BYE, requireNonNull( listener ) );
+ }
+
+ public void setStopOnNextTestListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_STOP_ON_NEXT_TEST, requireNonNull( listener ) );
+ }
+
+ public void setAcquireNextTestListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_NEXT_TEST, requireNonNull( listener ) );
+ }
+
+ public void setExitErrorEventListener( ForkedProcessExitErrorListener listener )
+ {
+ exitErrorEventListener = requireNonNull( listener );
+ }
+
+ public void notifyEvent( Event event )
+ {
+ ForkedProcessEventType eventType = event.getEventType();
+ if ( event.isControlCategory() )
+ {
+ ForkedProcessEventListener listener = controlEventListeners.get( eventType );
+ if ( listener != null )
+ {
+ listener.handle();
+ }
+ }
+ else if ( event.isConsoleErrorCategory() )
+ {
+ if ( consoleErrorEventListener != null )
+ {
+ consoleErrorEventListener.handle( ( ( ConsoleErrorEvent ) event ).getStackTraceWriter() );
+ }
+ }
+ else if ( event.isConsoleCategory() )
+ {
+ ForkedProcessStringEventListener listener = consoleEventListeners.get( eventType );
+ if ( listener != null )
+ {
+ listener.handle( ( (AbstractConsoleEvent) event ).getMessage() );
+ }
+ }
+ else if ( event.isStandardStreamCategory() )
+ {
+ boolean newLine = eventType == BOOTERCODE_STDOUT_NEW_LINE || eventType == BOOTERCODE_STDERR_NEW_LINE;
+ AbstractStandardStreamEvent standardStreamEvent = (AbstractStandardStreamEvent) event;
+ ForkedProcessStandardOutErrEventListener listener = stdOutErrEventListeners.get( eventType );
+ if ( listener != null )
+ {
+ listener.handle( standardStreamEvent.getRunMode(), standardStreamEvent.getMessage(), newLine );
+ }
+ }
+ else if ( event.isSysPropCategory() )
+ {
+ SystemPropertyEvent systemPropertyEvent = (SystemPropertyEvent) event;
+ RunMode runMode = systemPropertyEvent.getRunMode();
+ String key = systemPropertyEvent.getKey();
+ String value = systemPropertyEvent.getValue();
+ if ( propertyEventListener != null )
+ {
+ propertyEventListener.handle( runMode, key, value );
+ }
+ }
+ else if ( event.isTestCategory() )
+ {
+ ForkedProcessReportEventListener listener = reportEventListeners.get( eventType );
+ AbstractTestControlEvent testControlEvent = (AbstractTestControlEvent) event;
+ RunMode mode = testControlEvent.getRunMode();
+ ReportEntry reportEntry = testControlEvent.getReportEntry();
+ if ( listener != null )
+ {
+ listener.handle( mode, reportEntry );
+ }
+ }
+ else if ( event.isJvmExitError() )
+ {
+ JvmExitErrorEvent jvmExitErrorEvent = (JvmExitErrorEvent) event;
+ if ( exitErrorEventListener != null )
+ {
+ exitErrorEventListener.handle( jvmExitErrorEvent.getStackTraceWriter() );
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException( "Unknown event type " + eventType );
+ }
+ }
+}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
index b14c38c..a8b4b0b 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
@@ -19,11 +19,13 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* under the License.
*/
+import org.apache.maven.surefire.report.StackTraceWriter;
+
/**
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
public interface ForkedProcessExitErrorListener
{
- void handle( String exceptionMessage, String smartTrimmedStackTrace, String stackTrace );
+ void handle( StackTraceWriter stackTrace );
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
index f54cc40..81bf53f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
@@ -19,11 +19,15 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* under the License.
*/
+import org.apache.maven.surefire.report.StackTraceWriter;
+
+import javax.annotation.Nonnull;
+
/**
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
public interface ForkedProcessStackTraceEventListener
{
- void handle( String msg, String smartStackTrace, String stackTrace );
+ void handle( @Nonnull StackTraceWriter stackTrace );
}
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..bc0bc7c 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,9 @@ 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.EventHandler;
+
+import javax.annotation.Nonnull;
/**
* Used by forked JMV, see {@link org.apache.maven.plugin.surefire.booterclient.ForkStarter}.
@@ -30,7 +32,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 EventHandler<String>
{
private final DefaultReporterFactory defaultReporterFactory;
@@ -40,7 +42,7 @@ public final class NativeStdErrStreamConsumer
}
@Override
- public void consumeLine( String line )
+ public void handleEvent( @Nonnull String line )
{
InPluginProcessDumpSingleton.getSingleton()
.dumpStreamText( line, defaultReporterFactory.getReportsDirectory() );
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
similarity index 62%
copy from maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
index f54cc40..1f915ae 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdOutStreamConsumer.java
@@ -9,7 +9,7 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* "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,11 +19,25 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* under the License.
*/
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.extensions.StdOutStreamLine;
+
/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M4
+ *
*/
-public interface ForkedProcessStackTraceEventListener
+public class NativeStdOutStreamConsumer
+ implements StdOutStreamLine
{
- void handle( String msg, String smartStackTrace, String stackTrace );
+ 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..9c72a04 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
@@ -19,9 +19,12 @@ package org.apache.maven.plugin.surefire.booterclient.output;
* under the License.
*/
+import org.apache.maven.surefire.eventapi.Event;
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,13 +39,13 @@ import static java.lang.Thread.currentThread;
* @author Kristian Rosenvold
*/
public final class ThreadedStreamConsumer
- implements StreamConsumer, Closeable
+ implements EventHandler<Event>, Closeable
{
- private static final String END_ITEM = "";
+ private static final Event END_ITEM = new FinalEvent();
private static final int ITEM_LIMIT_BEFORE_SLEEP = 10_000;
- private final BlockingQueue<String> items = new ArrayBlockingQueue<>( ITEM_LIMIT_BEFORE_SLEEP );
+ private final BlockingQueue<Event> items = new ArrayBlockingQueue<>( ITEM_LIMIT_BEFORE_SLEEP );
private final AtomicBoolean stop = new AtomicBoolean();
@@ -53,17 +56,17 @@ public final class ThreadedStreamConsumer
final class Pumper
implements Runnable
{
- private final StreamConsumer target;
+ private final EventHandler<Event> target;
private final MultipleFailureException errors = new MultipleFailureException();
- Pumper( StreamConsumer target )
+ Pumper( EventHandler<Event> target )
{
this.target = target;
}
/**
- * Calls {@link ForkClient#consumeLine(String)} which may throw any {@link RuntimeException}.<br>
+ * Calls {@link ForkClient#handleEvent(Event)} which may throw any {@link RuntimeException}.<br>
* Even if {@link ForkClient} is not fault-tolerant, this method MUST be fault-tolerant and thus the
* try-catch block must be inside of the loop which prevents from loosing events from {@link StreamConsumer}.
* <br>
@@ -80,12 +83,12 @@ public final class ThreadedStreamConsumer
{
try
{
- String item = ThreadedStreamConsumer.this.items.take();
+ Event item = ThreadedStreamConsumer.this.items.take();
if ( shouldStopQueueing( item ) )
{
return;
}
- target.consumeLine( item );
+ target.handleEvent( item );
}
catch ( Throwable t )
{
@@ -105,7 +108,7 @@ public final class ThreadedStreamConsumer
}
}
- public ThreadedStreamConsumer( StreamConsumer target )
+ public ThreadedStreamConsumer( EventHandler<Event> target )
{
pumper = new Pumper( target );
thread = DaemonThreadFactory.newDaemonThread( pumper, "ThreadedStreamConsumer" );
@@ -113,7 +116,7 @@ public final class ThreadedStreamConsumer
}
@Override
- public void consumeLine( String s )
+ public void handleEvent( @Nonnull Event event )
{
if ( stop.get() )
{
@@ -127,7 +130,7 @@ public final class ThreadedStreamConsumer
try
{
- items.put( s );
+ items.put( event );
}
catch ( InterruptedException e )
{
@@ -164,8 +167,61 @@ public final class ThreadedStreamConsumer
* @param item element from <code>items</code>
* @return {@code true} if tail of the queue
*/
- private boolean shouldStopQueueing( String item )
+ private boolean shouldStopQueueing( Event item )
{
return item == END_ITEM;
}
+
+ /**
+ *
+ */
+ private static class FinalEvent extends Event
+ {
+ FinalEvent()
+ {
+ super( null );
+ }
+
+ @Override
+ public boolean isControlCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isConsoleCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isConsoleErrorCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isStandardStreamCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isSysPropCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isTestCategory()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isJvmExitError()
+ {
+ return false;
+ }
+ }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
new file mode 100644
index 0000000..cc33c6c
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
@@ -0,0 +1,441 @@
+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.commons.codec.binary.Base64;
+import org.apache.maven.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.ForkedProcessEventType;
+import org.apache.maven.surefire.eventapi.ConsoleDebugEvent;
+import org.apache.maven.surefire.eventapi.ConsoleErrorEvent;
+import org.apache.maven.surefire.eventapi.ConsoleInfoEvent;
+import org.apache.maven.surefire.eventapi.ConsoleWarningEvent;
+import org.apache.maven.surefire.eventapi.ControlByeEvent;
+import org.apache.maven.surefire.eventapi.ControlNextTestEvent;
+import org.apache.maven.surefire.eventapi.ControlStopOnNextTestEvent;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.eventapi.JvmExitErrorEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamErrEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamErrWithNewLineEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamOutEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamOutWithNewLineEvent;
+import org.apache.maven.surefire.eventapi.SystemPropertyEvent;
+import org.apache.maven.surefire.eventapi.TestAssumptionFailureEvent;
+import org.apache.maven.surefire.eventapi.TestErrorEvent;
+import org.apache.maven.surefire.eventapi.TestFailedEvent;
+import org.apache.maven.surefire.eventapi.TestSkippedEvent;
+import org.apache.maven.surefire.eventapi.TestStartingEvent;
+import org.apache.maven.surefire.eventapi.TestSucceededEvent;
+import org.apache.maven.surefire.eventapi.TestsetCompletedEvent;
+import org.apache.maven.surefire.eventapi.TestsetStartingEvent;
+import org.apache.maven.surefire.extensions.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.MAGIC_NUMBER;
+import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
+import static org.apache.maven.surefire.report.RunMode.MODES;
+
+/**
+ *
+ */
+public class EventConsumerThread extends CloseableDaemonThread
+{
+ private static final String PRINTABLE_JVM_NATIVE_STREAM = "Listening for transport dt_socket at address:";
+ private static final Base64 BASE64 = new Base64();
+
+ private final ReadableByteChannel channel;
+ private final EventHandler<Event> eventHandler;
+ private final CountdownCloseable countdownCloseable;
+ private final ConsoleLogger logger;
+ private volatile boolean disabled;
+
+ public EventConsumerThread( @Nonnull String threadName,
+ @Nonnull ReadableByteChannel channel,
+ @Nonnull EventHandler<Event> eventHandler,
+ @Nonnull CountdownCloseable countdownCloseable,
+ @Nonnull ConsoleLogger logger )
+ {
+ super( threadName );
+ this.channel = channel;
+ this.eventHandler = eventHandler;
+ this.countdownCloseable = countdownCloseable;
+ this.logger = logger;
+ }
+
+ @Override
+ public void run()
+ {
+ try ( ReadableByteChannel stream = channel;
+ CountdownCloseable c = countdownCloseable; )
+ {
+ decode();
+ }
+ catch ( IOException e )
+ {
+ // not needed
+ }
+ }
+
+ @Override
+ public void disable()
+ {
+ disabled = true;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ channel.close();
+ }
+
+ @SuppressWarnings( "checkstyle:innerassignment" )
+ private void decode() throws IOException
+ {
+ List<String> tokens = new ArrayList<>();
+ StringBuilder line = new StringBuilder();
+ StringBuilder token = new StringBuilder( MAGIC_NUMBER.length() );
+ ByteBuffer buffer = ByteBuffer.allocate( 1 );
+ boolean endOfStream;
+
+ start:
+ do
+ {
+ line.setLength( 0 );
+ tokens.clear();
+ token.setLength( 0 );
+ FrameCompletion completion = null;
+ for ( boolean frameStarted = false; !( endOfStream = channel.read( buffer ) == -1 ) ; completion = null )
+ {
+ buffer.flip();
+ char c = (char) buffer.get();
+ buffer.clear();
+
+ if ( c == '\n' || c == '\r' )
+ {
+ printExistingLine( line );
+ continue start;
+ }
+
+ line.append( c );
+
+ if ( !frameStarted )
+ {
+ if ( c == ':' )
+ {
+ frameStarted = true;
+ token.setLength( 0 );
+ tokens.clear();
+ }
+ }
+ else
+ {
+ if ( c == ':' )
+ {
+ tokens.add( token.toString() );
+ token.setLength( 0 );
+ completion = frameCompleteness( tokens );
+ if ( completion == FrameCompletion.COMPLETE )
+ {
+ line.setLength( 0 );
+ break;
+ }
+ else if ( completion == FrameCompletion.MALFORMED )
+ {
+ printExistingLine( line );
+ continue start;
+ }
+ }
+ else
+ {
+ token.append( c );
+ }
+ }
+ }
+
+ if ( completion == FrameCompletion.COMPLETE )
+ {
+ Event event = toEvent( tokens );
+ if ( !disabled && event != null )
+ {
+ eventHandler.handleEvent( event );
+ }
+ }
+
+ if ( endOfStream )
+ {
+ printExistingLine( line );
+ return;
+ }
+ }
+ while ( true );
+ }
+
+ private void printExistingLine( StringBuilder line )
+ {
+ if ( line.length() != 0 )
+ {
+ String s = line.toString();
+ if ( s.contains( PRINTABLE_JVM_NATIVE_STREAM ) )
+ {
+ logger.info( s );
+ }
+ else
+ {
+ logger.error( s );
+ }
+ }
+ }
+
+ private Event toEvent( List<String> tokensInFrame )
+ {
+ Iterator<String> tokens = tokensInFrame.iterator();
+ String header = tokens.next();
+ assert header != null;
+
+ ForkedProcessEventType event = ForkedProcessEventType.byOpcode( tokens.next() );
+
+ if ( event == null )
+ {
+ return null;
+ }
+
+ if ( event.isControlCategory() )
+ {
+ switch ( event )
+ {
+ case BOOTERCODE_BYE:
+ return new ControlByeEvent();
+ case BOOTERCODE_STOP_ON_NEXT_TEST:
+ return new ControlStopOnNextTestEvent();
+ case BOOTERCODE_NEXT_TEST:
+ return new ControlNextTestEvent();
+ default:
+ throw new IllegalStateException( "Unknown enum " + event );
+ }
+ }
+ else if ( event.isConsoleErrorCategory() || event.isJvmExitError() )
+ {
+ Charset encoding = Charset.forName( tokens.next() );
+ StackTraceWriter stackTraceWriter = decodeTrace( encoding, tokens.next(), tokens.next(), tokens.next() );
+ return event.isConsoleErrorCategory()
+ ? new ConsoleErrorEvent( stackTraceWriter )
+ : new JvmExitErrorEvent( stackTraceWriter );
+ }
+ else if ( event.isConsoleCategory() )
+ {
+ Charset encoding = Charset.forName( tokens.next() );
+ String msg = decode( tokens.next(), encoding );
+ switch ( event )
+ {
+ case BOOTERCODE_CONSOLE_INFO:
+ return new ConsoleInfoEvent( msg );
+ case BOOTERCODE_CONSOLE_DEBUG:
+ return new ConsoleDebugEvent( msg );
+ case BOOTERCODE_CONSOLE_WARNING:
+ return new ConsoleWarningEvent( msg );
+ default:
+ throw new IllegalStateException( "Unknown enum " + event );
+ }
+ }
+ else if ( event.isStandardStreamCategory() )
+ {
+ RunMode mode = MODES.get( tokens.next() );
+ Charset encoding = Charset.forName( tokens.next() );
+ String output = decode( tokens.next(), encoding );
+ switch ( event )
+ {
+ case BOOTERCODE_STDOUT:
+ return new StandardStreamOutEvent( mode, output );
+ case BOOTERCODE_STDOUT_NEW_LINE:
+ return new StandardStreamOutWithNewLineEvent( mode, output );
+ case BOOTERCODE_STDERR:
+ return new StandardStreamErrEvent( mode, output );
+ case BOOTERCODE_STDERR_NEW_LINE:
+ return new StandardStreamErrWithNewLineEvent( mode, output );
+ default:
+ throw new IllegalStateException( "Unknown enum " + event );
+ }
+ }
+ else if ( event.isSysPropCategory() )
+ {
+ RunMode mode = MODES.get( tokens.next() );
+ Charset encoding = Charset.forName( tokens.next() );
+ String key = decode( tokens.next(), encoding );
+ String value = decode( tokens.next(), encoding );
+ return new SystemPropertyEvent( mode, key, value );
+ }
+ else if ( event.isTestCategory() )
+ {
+ RunMode mode = MODES.get( tokens.next() );
+ Charset encoding = Charset.forName( tokens.next() );
+ TestSetReportEntry reportEntry =
+ decodeReportEntry( encoding, tokens.next(), tokens.next(), tokens.next(), tokens.next(),
+ tokens.next(), tokens.next(), tokens.next(), tokens.next(), tokens.next(), tokens.next() );
+
+ switch ( event )
+ {
+ case BOOTERCODE_TESTSET_STARTING:
+ return new TestsetStartingEvent( mode, reportEntry );
+ case BOOTERCODE_TESTSET_COMPLETED:
+ return new TestsetCompletedEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_STARTING:
+ return new TestStartingEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_SUCCEEDED:
+ return new TestSucceededEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_FAILED:
+ return new TestFailedEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_SKIPPED:
+ return new TestSkippedEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_ERROR:
+ return new TestErrorEvent( mode, reportEntry );
+ case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
+ return new TestAssumptionFailureEvent( mode, reportEntry );
+ default:
+ throw new IllegalStateException( "Unknown enum " + event );
+ }
+ }
+
+ throw new IllegalStateException( "Missing a branch for the event type " + event );
+ }
+
+ private static FrameCompletion frameCompleteness( List<String> tokens )
+ {
+ if ( !tokens.isEmpty() && !MAGIC_NUMBER.equals( tokens.get( 0 ) ) )
+ {
+ return FrameCompletion.MALFORMED;
+ }
+
+ if ( tokens.size() >= 2 )
+ {
+ String opcode = tokens.get( 1 );
+ ForkedProcessEventType event = ForkedProcessEventType.byOpcode( opcode );
+ if ( event == null )
+ {
+ return FrameCompletion.MALFORMED;
+ }
+ else if ( event.isControlCategory() )
+ {
+ return FrameCompletion.COMPLETE;
+ }
+ else if ( event.isConsoleErrorCategory() )
+ {
+ return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ else if ( event.isConsoleCategory() )
+ {
+ return tokens.size() == 4 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ else if ( event.isStandardStreamCategory() )
+ {
+ return tokens.size() == 5 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ else if ( event.isSysPropCategory() )
+ {
+ return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ else if ( event.isTestCategory() )
+ {
+ return tokens.size() == 14 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ else if ( event.isJvmExitError() )
+ {
+ return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ }
+ }
+ return FrameCompletion.NOT_COMPLETE;
+ }
+
+ static String decode( String line, Charset encoding )
+ {
+ // ForkedChannelEncoder is encoding the stream with US_ASCII
+ return line == null || "-".equals( line )
+ ? null
+ : new String( BASE64.decode( line.getBytes( US_ASCII ) ), encoding );
+ }
+
+ private static StackTraceWriter decodeTrace( Charset encoding, String encTraceMessage,
+ String encSmartTrimmedStackTrace, String encStackTrace )
+ {
+ String traceMessage = decode( encTraceMessage, encoding );
+ String stackTrace = decode( encStackTrace, encoding );
+ String smartTrimmedStackTrace = decode( encSmartTrimmedStackTrace, encoding );
+ boolean exists = traceMessage != null || stackTrace != null || smartTrimmedStackTrace != null;
+ return exists ? new DeserializedStacktraceWriter( traceMessage, smartTrimmedStackTrace, stackTrace ) : null;
+ }
+
+ static TestSetReportEntry decodeReportEntry( Charset encoding,
+ // ReportEntry:
+ String encSource, String encSourceText, String encName,
+ String encNameText, String encGroup, String encMessage,
+ String encTimeElapsed,
+ // StackTraceWriter:
+ String encTraceMessage,
+ String encSmartTrimmedStackTrace, String encStackTrace )
+ throws NumberFormatException
+ {
+ if ( encoding == null )
+ {
+ // corrupted or incomplete stream
+ return null;
+ }
+
+ String source = decode( encSource, encoding );
+ String sourceText = decode( encSourceText, encoding );
+ String name = decode( encName, encoding );
+ String nameText = decode( encNameText, encoding );
+ String group = decode( encGroup, encoding );
+ StackTraceWriter stackTraceWriter =
+ decodeTrace( encoding, encTraceMessage, encSmartTrimmedStackTrace, encStackTrace );
+ Integer elapsed = decodeToInteger( encTimeElapsed );
+ String message = decode( encMessage, encoding );
+ return reportEntry( source, sourceText, name, nameText,
+ group, stackTraceWriter, elapsed, message, Collections.<String, String>emptyMap() );
+ }
+
+ static Integer decodeToInteger( String line )
+ {
+ return line == null || "-".equals( line ) ? null : Integer.decode( line );
+ }
+
+ /**
+ * Determines whether the frame is complete or malformed.
+ */
+ private enum FrameCompletion
+ {
+ NOT_COMPLETE,
+ COMPLETE,
+ MALFORMED
+ }
+}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
new file mode 100644
index 0000000..a554edf
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
@@ -0,0 +1,89 @@
+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.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+
+import javax.annotation.Nonnull;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * The main purpose of this class is to bind the
+ * {@link #bindCommandReader(CommandReader, WritableByteChannel) command reader} reading the commands from
+ * {@link CommandReader}, serializing them and writing the stream to the
+ * {@link WritableByteChannel sub-process}. It binds the
+ * {@link #bindEventHandler(EventHandler, CountdownCloseable, ReadableByteChannel) event handler} deserializing
+ * a received event and sends the event object to the {@link EventHandler event handler}.
+ */
+final class LegacyForkChannel extends ForkChannel
+{
+ private final ConsoleLogger logger;
+
+ protected LegacyForkChannel( int forkChannelId, ConsoleLogger logger )
+ {
+ super( forkChannelId );
+ this.logger = logger;
+ }
+
+ @Override
+ public void connectToClient()
+ {
+ }
+
+ @Override
+ public String getForkNodeConnectionString()
+ {
+ return "pipe://" + getForkChannelId();
+ }
+
+ @Override
+ public boolean useStdOut()
+ {
+ return true;
+ }
+
+ @Override
+ public CloseableDaemonThread bindCommandReader( @Nonnull CommandReader commands,
+ WritableByteChannel stdIn )
+ {
+ return new StreamFeeder( "std-in-fork-" + getForkChannelId(), stdIn, commands, logger );
+ }
+
+ @Override
+ public CloseableDaemonThread bindEventHandler( @Nonnull EventHandler<Event> eventHandler,
+ @Nonnull CountdownCloseable countdownCloseable,
+ ReadableByteChannel stdOut )
+ {
+ return new EventConsumerThread( "fork-" + getForkChannelId() + "-event-thread-", stdOut,
+ eventHandler, countdownCloseable, logger );
+ }
+
+ @Override
+ public void close()
+ {
+ }
+}
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkNodeFactory.java
similarity index 58%
copy from surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkNodeFactory.java
index df9cca1..ca2010b 100644
--- a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.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.extensions.util;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,20 +19,22 @@ package org.apache.maven.surefire.extensions.util;
* under the License.
*/
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
/**
- *
+ * The factory of {@link LegacyForkChannel}.
*/
-public class JUnit4SuiteTest extends TestCase
+public class LegacyForkNodeFactory implements ForkNodeFactory
{
- public static Test suite()
+ @Nonnull
+ @Override
+ public ForkChannel createForkChannel( @Nonnegative int forkChannelId, ConsoleLogger logger )
{
- TestSuite suite = new TestSuite();
- suite.addTest( new JUnit4TestAdapter( CommandlineExecutorTest.class ) );
- return suite;
+ return new LegacyForkChannel( forkChannelId, logger );
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java
new file mode 100644
index 0000000..604ca33
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java
@@ -0,0 +1,203 @@
+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.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.extensions.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.util.internal.ImmutableMap;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.WritableByteChannel;
+import java.util.HashMap;
+import java.util.Map;
+
+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.MAGIC_NUMBER;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+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;
+
+/**
+ * Commands which are sent from plugin to 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)]*
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M5
+ */
+public class StreamFeeder extends CloseableDaemonThread
+{
+ private static final Map<MasterProcessCommand, String> COMMAND_OPCODES = opcodesToStrings();
+
+ private final WritableByteChannel channel;
+ private final CommandReader commandReader;
+ private final ConsoleLogger logger;
+
+ private volatile boolean disabled;
+ private volatile Throwable exception;
+
+ public StreamFeeder( @Nonnull String threadName, @Nonnull WritableByteChannel channel,
+ @Nonnull CommandReader commandReader, @Nonnull ConsoleLogger logger )
+ {
+ super( threadName );
+ this.channel = channel;
+ this.commandReader = commandReader;
+ this.logger = logger;
+ }
+
+ @Override
+ @SuppressWarnings( "checkstyle:innerassignment" )
+ public void run()
+ {
+ try ( WritableByteChannel c = channel )
+ {
+ for ( Command cmd; ( cmd = commandReader.readNextCommand() ) != null; )
+ {
+ if ( !disabled )
+ {
+ MasterProcessCommand cmdType = cmd.getCommandType();
+ byte[] data = cmdType.hasDataType() ? encode( cmdType, cmd.getData() ) : encode( cmdType );
+ c.write( ByteBuffer.wrap( data ) );
+ }
+ }
+ }
+ catch ( ClosedChannelException e )
+ {
+ // closed externally
+ }
+ catch ( IOException | NonWritableChannelException e )
+ {
+ exception = e.getCause() == null ? e : e.getCause();
+ }
+ catch ( IllegalArgumentException e )
+ {
+ logger.error( e.getLocalizedMessage() );
+ }
+ }
+
+ public void disable()
+ {
+ disabled = true;
+ }
+
+ public Throwable getException()
+ {
+ return exception;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ channel.close();
+ }
+
+ /**
+ * Public method for testing purposes.
+ *
+ * @param cmdType command type
+ * @param data data to encode
+ * @return command with data encoded to bytes
+ */
+ public static byte[] encode( MasterProcessCommand cmdType, String data )
+ {
+ if ( !cmdType.hasDataType() )
+ {
+ throw new IllegalArgumentException( "cannot use data without data type" );
+ }
+
+ if ( cmdType.getDataType() != String.class )
+ {
+ throw new IllegalArgumentException( "Data type can be only " + String.class );
+ }
+
+ return encode( COMMAND_OPCODES.get( cmdType ), data )
+ .toString()
+ .getBytes( US_ASCII );
+ }
+
+ /**
+ * Public method for testing purposes.
+ *
+ * @param cmdType command type
+ * @return command without data encoded to bytes
+ */
+ public static byte[] encode( MasterProcessCommand cmdType )
+ {
+ if ( cmdType.getDataType() != Void.class )
+ {
+ throw new IllegalArgumentException( "Data type can be only " + cmdType.getDataType() );
+ }
+
+ return encode( COMMAND_OPCODES.get( cmdType ), null )
+ .toString()
+ .getBytes( US_ASCII );
+ }
+
+ /**
+ * 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( ':' )
+ .append( MAGIC_NUMBER )
+ .append( ':' )
+ .append( operation );
+
+ if ( data != null )
+ {
+ s.append( ':' )
+ .append( data );
+ }
+
+ return s.append( ':' );
+ }
+
+ private static Map<MasterProcessCommand, String> opcodesToStrings()
+ {
+ Map<MasterProcessCommand, String> opcodes = new HashMap<>();
+ opcodes.put( RUN_CLASS, "run-testclass" );
+ opcodes.put( TEST_SET_FINISHED, "testset-finished" );
+ opcodes.put( SKIP_SINCE_NEXT_TEST, "skip-since-next-test" );
+ opcodes.put( SHUTDOWN, "shutdown" );
+ opcodes.put( NOOP, "noop" );
+ opcodes.put( BYE_ACK, "bye-ack" );
+ return new ImmutableMap<>( opcodes );
+ }
+}
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..0aa790c
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
@@ -0,0 +1,140 @@
+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.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketOption;
+import java.nio.channels.Channel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+
+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.ServerSocketChannel.open;
+
+/**
+ * The TCP/IP server accepting only one client connection. The forked JVM connects to the server using the
+ * {@link #getForkNodeConnectionString() connection string}.
+ * The main purpose of this class is to {@link #connectToClient() conect with tthe client}, bind the
+ * {@link #bindCommandReader(CommandReader, WritableByteChannel) command reader} to the internal socket's
+ * {@link java.io.InputStream}, and bind the
+ * {@link #bindEventHandler(EventHandler, CountdownCloseable, ReadableByteChannel) event handler} writing the event
+ * objects to the {@link EventHandler event handler}.
+ * <br>
+ * The objects {@link WritableByteChannel} and {@link ReadableByteChannel} are forked process streams
+ * (standard input and output). Both are ignored in this implementation but they are used in {@link LegacyForkChannel}.
+ * <br>
+ * The channel is closed after the forked JVM has finished normally or the shutdown hook is executed in the plugin.
+ */
+final class SurefireForkChannel extends ForkChannel
+{
+ private static final byte[] LOCAL_LOOPBACK_IP_ADDRESS = new byte[]{127, 0, 0, 1};
+
+ private final ConsoleLogger logger;
+ private final ServerSocketChannel server;
+ private final int localPort;
+ private volatile SocketChannel channel;
+
+ SurefireForkChannel( int forkChannelId, ConsoleLogger logger ) throws IOException
+ {
+ super( forkChannelId );
+ this.logger = logger;
+ server = open();
+ setTrueOptions( SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE );
+ InetAddress ip = Inet4Address.getByAddress( LOCAL_LOOPBACK_IP_ADDRESS );
+ server.bind( new InetSocketAddress( ip, 0 ), 1 );
+ localPort = ( (InetSocketAddress) server.getLocalAddress() ).getPort();
+ }
+
+ @Override
+ public void connectToClient() throws IOException
+ {
+ if ( channel != null )
+ {
+ throw new IllegalStateException( "already accepted TCP client connection" );
+ }
+ channel = server.accept();
+ }
+
+ @SafeVarargs
+ private final void setTrueOptions( SocketOption<Boolean>... options ) throws IOException
+ {
+ for ( SocketOption<Boolean> option : options )
+ {
+ if ( server.supportedOptions().contains( option ) )
+ {
+ server.setOption( option, true );
+ }
+ }
+ }
+
+ @Override
+ public String getForkNodeConnectionString()
+ {
+ return "tcp://127.0.0.1:" + localPort;
+ }
+
+ @Override
+ public boolean useStdOut()
+ {
+ return false;
+ }
+
+ @Override
+ public CloseableDaemonThread bindCommandReader( @Nonnull CommandReader commands,
+ WritableByteChannel stdIn )
+ {
+ return new StreamFeeder( "commands-fork-" + getForkChannelId(), channel, commands, logger );
+ }
+
+ @Override
+ public CloseableDaemonThread bindEventHandler( @Nonnull EventHandler<Event> eventHandler,
+ @Nonnull CountdownCloseable countdownCloseable,
+ ReadableByteChannel stdOut )
+ {
+ return new EventConsumerThread( "fork-" + getForkChannelId() + "-event-thread-", channel,
+ eventHandler, countdownCloseable, logger );
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ //noinspection EmptyTryBlock
+ try ( Channel c1 = channel; Channel c2 = server )
+ {
+ // only close all channels
+ }
+ }
+}
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkNodeFactory.java
similarity index 56%
copy from surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkNodeFactory.java
index df9cca1..1c4aabc 100644
--- a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.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.extensions.util;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,20 +19,23 @@ package org.apache.maven.surefire.extensions.util;
* under the License.
*/
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.extensions.ForkChannel;
+import org.apache.maven.surefire.extensions.ForkNodeFactory;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import java.io.IOException;
/**
- *
+ * The factory of {@link SurefireForkChannel}.
*/
-public class JUnit4SuiteTest extends TestCase
+public class SurefireForkNodeFactory implements ForkNodeFactory
{
- public static Test suite()
+ @Nonnull
+ @Override
+ public ForkChannel createForkChannel( @Nonnegative int forkChannelId, ConsoleLogger logger ) throws IOException
{
- TestSuite suite = new TestSuite();
- suite.addTest( new JUnit4TestAdapter( CommandlineExecutorTest.class ) );
- return suite;
+ return new SurefireForkChannel( forkChannelId, logger );
}
}
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..abd896e 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;
@@ -180,11 +181,26 @@ public class AbstractSurefireMojoJava7PlusTest
"jar", "", handler );
loggerApi.setFile( mockFile( "surefire-logger-api.jar" ) );
+ Artifact spi = new DefaultArtifact( "org.apache.maven.surefire", "surefire-extensions-spi",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ spi.setFile( mockFile( "surefire-extensions-spi.jar" ) );
+
+ Artifact booter = new DefaultArtifact( "org.apache.maven.surefire", "surefire-booter",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ booter.setFile( mockFile( "surefire-booter.jar" ) );
+
+ Artifact utils = new DefaultArtifact( "org.apache.maven.surefire", "surefire-shared-utils",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ utils.setFile( mockFile( "surefire-shared-utils.jar" ) );
+
Map<String, Artifact> artifacts = new HashMap<>();
artifacts.put( "org.apache.maven.surefire:maven-surefire-common", common );
artifacts.put( "org.apache.maven.surefire:surefire-extensions-api", ext );
artifacts.put( "org.apache.maven.surefire:surefire-api", api );
artifacts.put( "org.apache.maven.surefire:surefire-logger-api", loggerApi );
+ artifacts.put( "org.apache.maven.surefire:surefire-extensions-spi", spi );
+ artifacts.put( "org.apache.maven.surefire:surefire-booter", booter );
+ artifacts.put( "org.apache.maven.surefire:surefire-shared-utils", utils );
when( mojo.getPluginArtifactMap() ).thenReturn( artifacts );
StartupConfiguration conf = invokeMethod( mojo, "newStartupConfigWithModularPath",
@@ -193,7 +209,6 @@ public class AbstractSurefireMojoJava7PlusTest
verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
verify( mojo, times( 1 ) ).isChildDelegation();
- verify( mojo, times( 1 ) ).getEffectiveForkCount();
verify( mojo, times( 1 ) ).getTestClassesDirectory();
verify( scanResult, times( 1 ) ).getClasses();
verifyStatic( ResolvePathsRequest.class, times( 1 ) );
@@ -219,8 +234,8 @@ public class AbstractSurefireMojoJava7PlusTest
"test(compact) classpath: non-modular.jar junit.jar hamcrest.jar",
"test(compact) modulepath: modular.jar classes",
"provider(compact) classpath: surefire-provider.jar",
- "in-process classpath: surefire-provider.jar maven-surefire-common.jar surefire-extensions-api.jar surefire-api.jar surefire-logger-api.jar",
- "in-process(compact) classpath: surefire-provider.jar maven-surefire-common.jar surefire-extensions-api.jar surefire-api.jar surefire-logger-api.jar"
+ "in-process classpath: surefire-provider.jar maven-surefire-common.jar surefire-booter.jar surefire-extensions-api.jar surefire-api.jar surefire-extensions-spi.jar surefire-logger-api.jar surefire-shared-utils.jar",
+ "in-process(compact) classpath: surefire-provider.jar maven-surefire-common.jar surefire-booter.jar surefire-extensions-api.jar surefire-api.jar surefire-extensions-spi.jar surefire-logger-api.jar surefire-shared-utils.jar"
);
assertThat( conf ).isNotNull();
@@ -632,6 +647,12 @@ public class AbstractSurefireMojoJava7PlusTest
}
@Override
+ protected ForkNodeFactory getForkNode()
+ {
+ return null;
+ }
+
+ @Override
protected Artifact getMojoArtifact()
{
return null;
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..0553de7 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;
@@ -312,11 +313,26 @@ public class AbstractSurefireMojoTest
createFromVersion( "1" ), "runtime", "jar", "", handler );
loggerApi.setFile( mockFile( "surefire-logger-api.jar" ) );
+ Artifact spi = new DefaultArtifact( "org.apache.maven.surefire", "surefire-extensions-spi",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ spi.setFile( mockFile( "surefire-extensions-spi.jar" ) );
+
+ Artifact booter = new DefaultArtifact( "org.apache.maven.surefire", "surefire-booter",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ booter.setFile( mockFile( "surefire-booter.jar" ) );
+
+ Artifact utils = new DefaultArtifact( "org.apache.maven.surefire", "surefire-shared-utils",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ utils.setFile( mockFile( "surefire-shared-utils.jar" ) );
+
Map<String, Artifact> providerArtifactsMap = new HashMap<>();
providerArtifactsMap.put( "org.apache.maven.surefire:maven-surefire-common", common );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-extensions-api", ext );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-api", api );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-logger-api", loggerApi );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-extensions-spi", spi );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-booter", booter );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-shared-utils", utils );
when( mojo.getPluginArtifactMap() )
.thenReturn( providerArtifactsMap );
@@ -358,7 +374,6 @@ public class AbstractSurefireMojoTest
verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
verify( mojo, times( 1 ) ).isChildDelegation();
- verify( mojo, times( 1 ) ).getEffectiveForkCount();
ArgumentCaptor<String> argument = ArgumentCaptor.forClass( String.class );
verify( logger, times( 6 ) ).debug( argument.capture() );
assertThat( argument.getAllValues() )
@@ -366,8 +381,8 @@ public class AbstractSurefireMojoTest
"provider classpath: surefire-provider.jar",
"test(compact) classpath: test-classes classes junit.jar hamcrest.jar",
"provider(compact) classpath: surefire-provider.jar",
- "in-process classpath: surefire-provider.jar maven-surefire-common.jar surefire-extensions-api.jar surefire-api.jar surefire-logger-api.jar",
- "in-process(compact) classpath: surefire-provider.jar maven-surefire-common.jar surefire-extensions-api.jar surefire-api.jar surefire-logger-api.jar"
+ "in-process classpath: surefire-provider.jar maven-surefire-common.jar surefire-booter.jar surefire-extensions-api.jar surefire-api.jar surefire-extensions-spi.jar surefire-logger-api.jar surefire-shared-utils.jar",
+ "in-process(compact) classpath: surefire-provider.jar maven-surefire-common.jar surefire-booter.jar surefire-extensions-api.jar surefire-api.jar surefire-extensions-spi.jar surefire-logger-api.jar surefire-shared-utils.jar"
);
assertThat( conf.getClassLoaderConfiguration() )
@@ -405,7 +420,7 @@ public class AbstractSurefireMojoTest
Artifact provider = new DefaultArtifact( "com.example", "provider", createFromVersion( "1" ), "runtime",
"jar", "", handler );
provider.setFile( mockFile( "original-test-provider.jar" ) );
- HashSet<Artifact> providerClasspath = new HashSet<>( asList( provider ) );
+ Set<Artifact> providerClasspath = singleton( provider );
when( providerInfo.getProviderClasspath() ).thenReturn( providerClasspath );
StartupConfiguration startupConfiguration = startupConfigurationForProvider( providerInfo );
@@ -448,11 +463,26 @@ public class AbstractSurefireMojoTest
createFromVersion( "1" ), "runtime", "jar", "", handler );
loggerApi.setFile( mockFile( "surefire-logger-api.jar" ) );
+ Artifact spi = new DefaultArtifact( "org.apache.maven.surefire", "surefire-extensions-spi",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ spi.setFile( mockFile( "surefire-extensions-spi.jar" ) );
+
+ Artifact booter = new DefaultArtifact( "org.apache.maven.surefire", "surefire-booter",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ booter.setFile( mockFile( "surefire-booter.jar" ) );
+
+ Artifact utils = new DefaultArtifact( "org.apache.maven.surefire", "surefire-shared-utils",
+ createFromVersion( "1" ), "runtime", "jar", "", handler );
+ utils.setFile( mockFile( "surefire-shared-utils.jar" ) );
+
Map<String, Artifact> providerArtifactsMap = new HashMap<>();
providerArtifactsMap.put( "org.apache.maven.surefire:maven-surefire-common", common );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-extensions-api", ext );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-api", api );
providerArtifactsMap.put( "org.apache.maven.surefire:surefire-logger-api", loggerApi );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-extensions-spi", spi );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-booter", booter );
+ providerArtifactsMap.put( "org.apache.maven.surefire:surefire-shared-utils", utils );
when( mojo.getPluginArtifactMap() ).thenReturn( providerArtifactsMap );
@@ -2121,6 +2151,12 @@ public class AbstractSurefireMojoTest
}
@Override
+ protected ForkNodeFactory getForkNode()
+ {
+ return null;
+ }
+
+ @Override
protected Artifact getMojoArtifact()
{
return new DefaultArtifact( "org.apache.maven.surefire", "maven-surefire-plugin", createFromVersion( "1" ),
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..10563a8 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
@@ -25,7 +25,6 @@ import org.apache.maven.surefire.shared.io.FileUtils;
import org.apache.maven.surefire.booter.BooterDeserializer;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
-import org.apache.maven.surefire.booter.ProcessCheckerType;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.booter.Shutdown;
@@ -52,6 +51,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import static org.apache.maven.surefire.booter.ProcessCheckerType.ALL;
import static org.apache.maven.surefire.cli.CommandLineOption.LOGGING_LEVEL_DEBUG;
import static org.apache.maven.surefire.cli.CommandLineOption.REACTOR_FAIL_FAST;
import static org.apache.maven.surefire.cli.CommandLineOption.SHOW_ERRORS;
@@ -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://1" );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
assertEquals( "51", (Object) booterDeserializer.getPluginPid() );
+ assertEquals( "pipe://1", booterDeserializer.getConnectionString() );
return booterDeserializer.deserialize();
}
@@ -285,8 +286,7 @@ public class BooterDeserializerProviderConfigurationTest
{
ClasspathConfiguration classpathConfiguration = new ClasspathConfiguration( true, true );
- return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, false,
- false, ProcessCheckerType.ALL );
+ return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL );
}
private File getTestSourceDirectory()
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..63f6162 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
@@ -20,24 +20,23 @@ package org.apache.maven.plugin.surefire.booterclient;
*/
import junit.framework.TestCase;
-import org.apache.maven.surefire.shared.io.FileUtils;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
import org.apache.maven.surefire.booter.BooterDeserializer;
+import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.ClasspathConfiguration;
-import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
-import org.apache.maven.surefire.booter.ProcessCheckerType;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
-import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.Shutdown;
+import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.report.ReporterConfiguration;
+import org.apache.maven.surefire.shared.io.FileUtils;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
import org.apache.maven.surefire.testset.RunOrderParameters;
import org.apache.maven.surefire.testset.TestArtifactInfo;
-import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.testset.TestListResolver;
+import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.RunOrder;
import org.junit.After;
import org.junit.Before;
@@ -50,6 +49,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import static org.apache.maven.surefire.booter.ProcessCheckerType.ALL;
import static org.apache.maven.surefire.cli.CommandLineOption.LOGGING_LEVEL_DEBUG;
import static org.apache.maven.surefire.cli.CommandLineOption.REACTOR_FAIL_FAST;
import static org.apache.maven.surefire.cli.CommandLineOption.SHOW_ERRORS;
@@ -105,7 +105,7 @@ public class BooterDeserializerStartupConfigurationTest
public void testProcessChecker() throws IOException
{
- assertEquals( ProcessCheckerType.ALL, getReloadedStartupConfiguration().getProcessChecker() );
+ assertEquals( ALL, getReloadedStartupConfiguration().getProcessChecker() );
}
private void assertCpConfigEquals( ClasspathConfiguration expectedConfiguration,
@@ -136,13 +136,13 @@ public class BooterDeserializerStartupConfigurationTest
public void testProcessCheckerAll() throws IOException
{
- assertEquals( ProcessCheckerType.ALL, getReloadedStartupConfiguration().getProcessChecker() );
+ assertEquals( ALL, getReloadedStartupConfiguration().getProcessChecker() );
}
public void testProcessCheckerNull() throws IOException
{
StartupConfiguration startupConfiguration = new StartupConfiguration( "com.provider", classpathConfiguration,
- getManifestOnlyJarForkConfiguration(), false, false, null );
+ getManifestOnlyJarForkConfiguration(), null );
assertNull( saveAndReload( startupConfiguration ).getProcessChecker() );
}
@@ -178,15 +178,15 @@ 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, "tcp://127.0.0.1:63003" );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
assertNull( booterDeserializer.getPluginPid() );
+ assertEquals( "tcp://127.0.0.1:63003", booterDeserializer.getConnectionString() );
return booterDeserializer.getStartupConfiguration();
}
private ProviderConfiguration getProviderConfiguration()
{
-
File cwd = new File( "." );
DirectoryScannerParameters directoryScannerParameters =
new DirectoryScannerParameters( cwd, new ArrayList<String>(), new ArrayList<String>(),
@@ -204,8 +204,7 @@ public class BooterDeserializerStartupConfigurationTest
private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
{
- return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, false,
- false, ProcessCheckerType.ALL );
+ return new StartupConfiguration( "com.provider", classpathConfiguration, classLoaderConfiguration, ALL );
}
private File getTestSourceDirectory()
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..45a6b4a 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 )
{
-
}
};
@@ -313,7 +307,7 @@ public class DefaultForkConfigurationTest
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
StartupConfiguration conf = new StartupConfiguration( "org.apache.maven.shadefire.surefire.MyProvider",
- cc, clc, false, false, null );
+ cc, clc, null );
StartupConfiguration confMock = spy( conf );
mockStatic( Relocator.class );
when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
@@ -334,7 +328,7 @@ public class DefaultForkConfigurationTest
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
StartupConfiguration conf =
- new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, false, false, null );
+ new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, null );
StartupConfiguration confMock = spy( conf );
mockStatic( Relocator.class );
when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
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..bc01ee8 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;
@@ -47,6 +48,7 @@ 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.mockito.Mockito.mock;
/**
*
@@ -55,10 +57,7 @@ public class ForkConfigurationTest
{
private static final StartupConfiguration STARTUP_CONFIG = new StartupConfiguration( "",
new ClasspathConfiguration( true, true ),
- new ClassLoaderConfiguration( true, true ),
- false,
- false,
- ALL );
+ new ClassLoaderConfiguration( true, true ), ALL );
private static int idx = 0;
@@ -91,7 +90,7 @@ public class ForkConfigurationTest
ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
emptyClasspath(), true, true );
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
- StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
+ StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
Commandline cli = config.createCommandLine( startup, 1, temporaryFolder() );
@@ -111,7 +110,7 @@ public class ForkConfigurationTest
ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
emptyClasspath(), true, true );
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
- StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
+ StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
assertTrue( commandLine.toString().contains( "abc def" ) );
@@ -126,7 +125,7 @@ public class ForkConfigurationTest
ClasspathConfiguration cpConfig = new ClasspathConfiguration( emptyClasspath(), emptyClasspath(),
emptyClasspath(), true, true );
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
- StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
+ StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, ALL );
ForkConfiguration config = getForkConfiguration( cwd.getCanonicalFile() );
Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
@@ -225,7 +224,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 +232,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/ForkStarterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
index e0874f0..55f789f 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
@@ -21,12 +21,13 @@ package org.apache.maven.plugin.surefire.booterclient;
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.OutputStreamFlushableCommandline;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
+import org.apache.maven.plugin.surefire.extensions.LegacyForkNodeFactory;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
@@ -37,6 +38,7 @@ import org.apache.maven.surefire.booter.ProviderConfiguration;
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.extensions.ForkNodeFactory;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.shared.compress.archivers.zip.Zip64Mode;
import org.apache.maven.surefire.shared.compress.archivers.zip.ZipArchiveEntry;
@@ -55,7 +57,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.Collections;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.Manifest;
import java.util.zip.Deflater;
@@ -170,12 +171,12 @@ public class ForkStarterTest
e.expectMessage( containsString( "VM crash or System.exit called?" ) );
Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
- int.class, AbstractForkInputStream.class, boolean.class};
+ int.class, AbstractCommandReader.class, ForkNodeFactory.class, boolean.class};
TestProvidingInputStream testProvidingInputStream = new TestProvidingInputStream( new ArrayDeque<String>() );
invokeMethod( forkStarter, "fork", types, null,
new PropertiesWrapper( Collections.<String, String>emptyMap() ),
- new ForkClient( reporterFactory, null, logger, new AtomicBoolean(), 1 ),
- new SurefireProperties(), 1, testProvidingInputStream, true );
+ new ForkClient( reporterFactory, null, 1 ),
+ new SurefireProperties(), 1, testProvidingInputStream, new LegacyForkNodeFactory(), true );
testProvidingInputStream.close();
}
@@ -224,12 +225,12 @@ public class ForkStarterTest
DefaultReporterFactory reporterFactory = new DefaultReporterFactory( startupReportConfiguration, logger, 1 );
Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
- int.class, AbstractForkInputStream.class, boolean.class};
+ int.class, AbstractCommandReader.class, ForkNodeFactory.class, boolean.class};
TestLessInputStream testLessInputStream = new TestLessInputStreamBuilder().build();
invokeMethod( forkStarter, "fork", types, null,
new PropertiesWrapper( Collections.<String, String>emptyMap() ),
- new ForkClient( reporterFactory, testLessInputStream, logger, new AtomicBoolean(), 1 ),
- new SurefireProperties(), 1, testLessInputStream, true );
+ new ForkClient( reporterFactory, testLessInputStream, 1 ),
+ new SurefireProperties(), 1, testLessInputStream, new LegacyForkNodeFactory(), true );
testLessInputStream.close();
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
index 79c6f0e..4ca19ad 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
@@ -19,14 +19,16 @@ package org.apache.maven.plugin.surefire.booterclient;
* under the License.
*/
-import junit.framework.Assert;
import junit.framework.TestCase;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThread;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
-import org.apache.maven.surefire.booter.ForkedChannelEncoder;
import org.apache.maven.surefire.booter.ForkingRunListener;
+import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
import org.apache.maven.surefire.report.CategorizedReportEntry;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
@@ -36,17 +38,23 @@ import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.report.TestSetReportEntry;
-import org.hamcrest.MatcherAssert;
+import javax.annotation.Nonnull;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
+import java.io.Closeable;
import java.io.PrintStream;
+import java.nio.channels.ReadableByteChannel;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
-import static org.hamcrest.Matchers.is;
+import static java.nio.channels.Channels.newChannel;
+import static org.mockito.Mockito.mock;
/**
* @author Kristian Rosenvold
@@ -74,8 +82,7 @@ public class ForkingRunListenerTest
content.reset();
}
- public void testSetStarting()
- throws ReporterException, IOException
+ public void testSetStarting() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
TestSetReportEntry expected = createDefaultReportEntry();
@@ -83,8 +90,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.SET_STARTING, expected );
}
- public void testSetCompleted()
- throws ReporterException, IOException
+ public void testSetCompleted() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
TestSetReportEntry expected = createDefaultReportEntry();
@@ -92,8 +98,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.SET_COMPLETED, expected );
}
- public void testStarting()
- throws ReporterException, IOException
+ public void testStarting() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createDefaultReportEntry();
@@ -101,8 +106,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_STARTING, expected );
}
- public void testSucceded()
- throws ReporterException, IOException
+ public void testSucceeded() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createDefaultReportEntry();
@@ -110,8 +114,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_SUCCEEDED, expected );
}
- public void testFailed()
- throws ReporterException, IOException
+ public void testFailed() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createReportEntryWithStackTrace();
@@ -119,8 +122,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
}
- public void testFailedWithCommaInMessage()
- throws ReporterException, IOException
+ public void testFailedWithCommaInMessage() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createReportEntryWithSpecialMessage( "We, the people" );
@@ -128,8 +130,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
}
- public void testFailedWithUnicodeEscapeInMessage()
- throws ReporterException, IOException
+ public void testFailedWithUnicodeEscapeInMessage() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createReportEntryWithSpecialMessage( "We, \\u0177 people" );
@@ -137,8 +138,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_FAILED, expected );
}
- public void testFailure()
- throws ReporterException, IOException
+ public void testFailure() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createDefaultReportEntry();
@@ -146,8 +146,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_ERROR, expected );
}
- public void testSkipped()
- throws ReporterException, IOException
+ public void testSkipped() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createDefaultReportEntry();
@@ -155,8 +154,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_SKIPPED, expected );
}
- public void testAssumptionFailure()
- throws ReporterException, IOException
+ public void testAssumptionFailure() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ReportEntry expected = createDefaultReportEntry();
@@ -164,8 +162,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.TEST_ASSUMPTION_FAIL, expected );
}
- public void testConsole()
- throws ReporterException, IOException
+ public void testConsole() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ConsoleLogger directConsoleReporter = (ConsoleLogger) standardTestRun.run();
@@ -173,8 +170,7 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.CONSOLE_INFO, "HeyYou" );
}
- public void testConsoleOutput()
- throws ReporterException, IOException
+ public void testConsoleOutput() throws Exception
{
final StandardTestRun standardTestRun = new StandardTestRun();
ConsoleOutputReceiver directConsoleReporter = (ConsoleOutputReceiver) standardTestRun.run();
@@ -182,30 +178,36 @@ public class ForkingRunListenerTest
standardTestRun.assertExpected( MockReporter.STDOUT, "HeyYou" );
}
- public void testSystemProperties()
- throws ReporterException, IOException
+ public void testSystemProperties() throws Exception
{
- final StandardTestRun standardTestRun = new StandardTestRun();
+ StandardTestRun standardTestRun = new StandardTestRun();
standardTestRun.run();
reset();
createForkingRunListener();
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
- NullConsoleLogger log = new NullConsoleLogger();
- ForkClient forkStreamClient =
- new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, new AtomicBoolean(), 1 );
+ ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
- forkStreamClient.consumeMultiLineContent( ":maven:surefire:std:out:sys-prop:normal-run:UTF-8:azE=:djE="
- + "\n:maven:surefire:std:out:sys-prop:normal-run:UTF-8:azI=:djI=" );
+ byte[] cmd = ":maven-surefire-event:sys-prop:normal-run:UTF-8:azE=:djE=:\n".getBytes();
+ for ( Event e : streamToEvent( cmd ) )
+ {
+ forkStreamClient.handleEvent( e );
+ }
+ cmd = "\n:maven-surefire-event:sys-prop:normal-run:UTF-8:azI=:djI=:\n".getBytes();
+ for ( Event e : streamToEvent( cmd ) )
+ {
+ forkStreamClient.handleEvent( e );
+ }
- MatcherAssert.assertThat( forkStreamClient.getTestVmSystemProperties().size(), is( 2 ) );
+ assertTrue( forkStreamClient.getTestVmSystemProperties().size() == 2 );
+ assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k1" ) );
+ assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k2" ) );
}
- public void testMultipleEntries()
- throws ReporterException, IOException
+ public void testMultipleEntries() throws Exception
{
- final StandardTestRun standardTestRun = new StandardTestRun();
+ StandardTestRun standardTestRun = new StandardTestRun();
standardTestRun.run();
reset();
@@ -218,11 +220,13 @@ public class ForkingRunListenerTest
forkingReporter.testSetCompleted( reportEntry );
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
- NullConsoleLogger log = new NullConsoleLogger();
ForkClient forkStreamClient =
- new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null, 1 );
+ new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
- forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
+ for ( Event e : streamToEvent( content.toByteArray() ) )
+ {
+ forkStreamClient.handleEvent( e );
+ }
final MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
final List<String> events = reporter.getEvents();
@@ -233,36 +237,82 @@ public class ForkingRunListenerTest
}
public void test2DifferentChannels()
- throws ReporterException, IOException
+ throws Exception
{
reset();
ReportEntry expected = createDefaultReportEntry();
- final SimpleReportEntry secondExpected = createAnotherDefaultReportEntry();
+ SimpleReportEntry secondExpected = createAnotherDefaultReportEntry();
- new ForkingRunListener( new ForkedChannelEncoder( printStream ), false )
+ new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( printStream ) ), false )
.testStarting( expected );
- new ForkingRunListener( new ForkedChannelEncoder( anotherPrintStream ), false )
+ new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( anotherPrintStream ) ), false )
.testSkipped( secondExpected );
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
NotifiableTestStream notifiableTestStream = new MockNotifiableTestStream();
- NullConsoleLogger log = new NullConsoleLogger();
- ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null, 1 );
- forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
+ ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, 1 );
+ for ( Event e : streamToEvent( content.toByteArray() ) )
+ {
+ forkStreamClient.handleEvent( e );
+ }
MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
- Assert.assertEquals( MockReporter.TEST_STARTING, reporter.getFirstEvent() );
- Assert.assertEquals( expected, reporter.getFirstData() );
- Assert.assertEquals( 1, reporter.getEvents().size() );
+ assertEquals( MockReporter.TEST_STARTING, reporter.getFirstEvent() );
+ assertEquals( expected, reporter.getFirstData() );
+ assertEquals( 1, reporter.getEvents().size() );
- forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null, 2 );
- forkStreamClient.consumeMultiLineContent( anotherContent.toString( "UTF-8" ) );
+ forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, 2 );
+ for ( Event e : streamToEvent( anotherContent.toByteArray() ) )
+ {
+ forkStreamClient.handleEvent( e );
+ }
MockReporter reporter2 = (MockReporter) forkStreamClient.getReporter();
- Assert.assertEquals( MockReporter.TEST_SKIPPED, reporter2.getFirstEvent() );
- Assert.assertEquals( secondExpected, reporter2.getFirstData() );
- Assert.assertEquals( 1, reporter2.getEvents().size() );
+ assertEquals( MockReporter.TEST_SKIPPED, reporter2.getFirstEvent() );
+ assertEquals( secondExpected, reporter2.getFirstData() );
+ assertEquals( 1, reporter2.getEvents().size() );
+ }
+
+ private static List<Event> streamToEvent( byte[] stream ) throws Exception
+ {
+ List<Event> events = new ArrayList<>();
+ EH handler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( stream ) );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, handler, countdown, logger ) )
+ {
+ t.start();
+ countdown.awaitClosed();
+ for ( int i = 0, size = handler.countEventsInCache(); i < size; i++ )
+ {
+ events.add( handler.pullEvent() );
+ }
+ assertEquals( 0, handler.countEventsInCache() );
+ return events;
+ }
+ }
+
+ private static class EH implements EventHandler<Event>
+ {
+ private final BlockingQueue<Event> cache = new LinkedBlockingQueue<>();
+
+ Event pullEvent() throws InterruptedException
+ {
+ return cache.poll( 1, TimeUnit.MINUTES );
+ }
+
+ int countEventsInCache()
+ {
+ return cache.size();
+ }
+
+ @Override
+ public void handleEvent( @Nonnull Event event )
+ {
+ cache.add( event );
+ }
}
// Todo: Test weird characters
@@ -312,7 +362,7 @@ public class ForkingRunListenerTest
private RunListener createForkingRunListener()
{
- return new ForkingRunListener( new ForkedChannelEncoder( printStream ), false );
+ return new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( printStream ) ), false );
}
private class StandardTestRun
@@ -326,15 +376,15 @@ public class ForkingRunListenerTest
return createForkingRunListener();
}
- public void clientReceiveContent()
- throws ReporterException, IOException
+ public void clientReceiveContent() throws Exception
{
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
- NullConsoleLogger log = new NullConsoleLogger();
- final ForkClient forkStreamClient =
- new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null, 1 );
- forkStreamClient.consumeMultiLineContent( content.toString( ) );
- reporter = (MockReporter) forkStreamClient.getReporter();
+ ForkClient handler = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
+ for ( Event e : streamToEvent( content.toByteArray() ) )
+ {
+ handler.handleEvent( e );
+ }
+ reporter = (MockReporter) handler.getReporter();
}
public String getFirstEvent()
@@ -347,8 +397,7 @@ public class ForkingRunListenerTest
return (ReportEntry) reporter.getData().get( 0 );
}
- private void assertExpected( String actionCode, ReportEntry expected )
- throws IOException, ReporterException
+ private void assertExpected( String actionCode, ReportEntry expected ) throws Exception
{
clientReceiveContent();
assertEquals( actionCode, getFirstEvent() );
@@ -368,8 +417,7 @@ public class ForkingRunListenerTest
}
}
- private void assertExpected( String actionCode, String expected )
- throws IOException, ReporterException
+ private void assertExpected( String actionCode, String expected ) throws Exception
{
clientReceiveContent();
assertEquals( actionCode, getFirstEvent() );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
index d90a128..dc435b5 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
@@ -34,15 +34,11 @@ public class MainClass
}
else
{
- System.out.println( ":maven:surefire:std:out:bye" );
- if ( System.in.read() == 0
- && System.in.read() == 0
- && System.in.read() == 0
- && System.in.read() == 5
- && System.in.read() == 0
- && System.in.read() == 0
- && System.in.read() == 0
- && System.in.read() == 0 )
+ System.out.println( ":maven-surefire-event:bye:" );
+ String byeAck = ":maven-surefire-command:bye-ack:";
+ byte[] cmd = new byte[byeAck.length()];
+ int len = System.in.read( cmd );
+ if ( len != -1 && new String( cmd, 0, len ).equals( byeAck ) )
{
System.exit( 0 );
}
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..cfa7dce 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
@@ -27,6 +27,7 @@ import org.apache.maven.surefire.booter.ForkedBooter;
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.extensions.ForkNodeFactory;
import org.junit.Test;
import java.io.File;
@@ -43,9 +44,10 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Files.readAllLines;
import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
-import static org.apache.maven.surefire.shared.utils.StringUtils.replace;
import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
+import static org.apache.maven.surefire.shared.utils.StringUtils.replace;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
/**
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
@@ -66,7 +68,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(), mock( ForkNodeFactory.class ) );
File patchFile = new File( "target" + separatorChar + "test-classes" );
File descriptor = new File( tmp, "module-info.class" );
@@ -141,8 +143,8 @@ public class ModularClasspathForkConfigurationTest
new ModularClasspathConfiguration( modularClasspath, testClasspathUrls, surefireClasspathUrls,
emptyClasspath(), true, true );
ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
- StartupConfiguration startupConfiguration =
- new StartupConfiguration( "JUnitCoreProvider", modularClasspathConfiguration, clc, true, true, null );
+ StartupConfiguration startupConfiguration = new StartupConfiguration( "JUnitCoreProvider",
+ modularClasspathConfiguration, clc, null );
OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
config.resolveClasspath( cli, ForkedBooter.class.getName(), startupConfiguration,
createTempFile( "surefire", "surefire-reports" ) );
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..2aab4c2 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,22 +21,24 @@ 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.LegacyMasterProcessChannelDecoder;
+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;
+import static java.nio.channels.Channels.newChannel;
import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
-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.apache.maven.plugin.surefire.extensions.StreamFeeder.encode;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -87,7 +89,7 @@ public class TestLessInputStreamBuilderTest
assertThat( is.availablePermits(), is( 1 ) );
is.beforeNextCommand();
assertThat( is.availablePermits(), is( 0 ) );
- assertThat( is.nextCommand(), is( NOOP ) );
+ assertThat( is.nextCommand(), is( Command.NOOP ) );
assertThat( is.availablePermits(), is( 0 ) );
e.expect( NoSuchElementException.class );
is.nextCommand();
@@ -105,7 +107,7 @@ public class TestLessInputStreamBuilderTest
assertThat( is.availablePermits(), is( 2 ) );
is.beforeNextCommand();
assertThat( is.availablePermits(), is( 1 ) );
- assertThat( is.nextCommand(), is( NOOP ) );
+ assertThat( is.nextCommand(), is( Command.NOOP ) );
assertThat( is.availablePermits(), is( 1 ) );
builder.getCachableCommands().skipSinceNextTest();
assertThat( is.availablePermits(), is( 1 ) );
@@ -123,7 +125,7 @@ public class TestLessInputStreamBuilderTest
builder.getCachableCommands().shutdown( EXIT );
assertThat( is.availablePermits(), is( 2 ) );
is.beforeNextCommand();
- assertThat( is.nextCommand(), is( NOOP ) );
+ assertThat( is.nextCommand(), is( Command.NOOP ) );
assertThat( is.availablePermits(), is( 1 ) );
is.beforeNextCommand();
assertThat( is.nextCommand().getCommandType(), is( SHUTDOWN ) );
@@ -137,15 +139,47 @@ 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();
+ if ( cmd != null )
+ {
+ MasterProcessCommand cmdType = cmd.getCommandType();
+ buffer = cmdType.hasDataType() ? encode( cmdType, cmd.getData() ) : encode( cmdType );
+ }
+ }
+
+ if ( buffer != null )
+ {
+ byte b = buffer[idx++];
+ if ( idx == buffer.length )
+ {
+ buffer = null;
+ idx = 0;
+ }
+ return b;
+ }
+ throw new IOException();
+ }
+ };
+ MasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
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..1d348ce 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,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.LegacyMasterProcessChannelDecoder;
+import org.apache.maven.plugin.surefire.extensions.StreamFeeder;
+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 +35,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
+import static java.nio.channels.Channels.newChannel;
+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.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertTrue;
/**
* Asserts that this stream properly reads bytes from queue.
@@ -46,14 +53,15 @@ import static org.hamcrest.Matchers.notNullValue;
*/
public class TestProvidingInputStreamTest
{
+ private static final int WAIT_LOOPS = 100;
@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 +71,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 +104,23 @@ 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 ) );
+
+ Command cmd = is.readNextCommand();
+ assertThat( cmd.getData(), is( nullValue() ) );
+ String stream = new String( StreamFeeder.encode( cmd.getCommandType() ), US_ASCII );
+
+ cmd = is.readNextCommand();
+ assertThat( cmd.getData(), is( nullValue() ) );
+ stream += new String( StreamFeeder.encode( cmd.getCommandType() ), US_ASCII );
+
+ assertThat( stream,
+ is( ":maven-surefire-command:testset-finished::maven-surefire-command:testset-finished:" ) );
+
+ boolean emptyStream = isInputStreamEmpty( is );
+
is.close();
- assertThat( is.read(), is( -1 ) );
+ assertTrue( emptyStream );
+ assertThat( is.readNextCommand(), is( nullValue() ) );
}
@Test
@@ -123,34 +138,55 @@ 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' ) );
+
+ Command cmd = is.readNextCommand();
+ assertThat( cmd.getData(), is( "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 : StreamFeeder.encode( cmd.getCommandType() );
+ }
+
+ if ( buffer != null )
+ {
+ byte b = buffer[idx++];
+ if ( idx == buffer.length )
+ {
+ buffer = null;
+ idx = 0;
+ }
+ return b;
+ }
+ throw new IOException();
+ }
+ };
+ MasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
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 +200,44 @@ 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;
+ if ( !( err instanceof InterruptedException ) )
+ {
+ System.err.println( err.toString() );
+ }
+ }
+ }
+ } );
+ t.start();
+ State state;
+ int loops = 0;
+ do
+ {
+ sleep( 100L );
+ state = t.getState();
+ }
+ while ( state == State.NEW && loops++ < WAIT_LOOPS );
+ t.interrupt();
+ return state == State.WAITING || state == State.TIMED_WAITING;
+ }
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
index 09230bb..60f6872 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
@@ -21,47 +21,79 @@ package org.apache.maven.plugin.surefire.booterclient.output;
import org.apache.maven.plugin.surefire.booterclient.MockReporter;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThread;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.surefire.booter.Shutdown;
+import org.apache.maven.surefire.eventapi.ConsoleDebugEvent;
+import org.apache.maven.surefire.eventapi.ConsoleErrorEvent;
+import org.apache.maven.surefire.eventapi.ConsoleInfoEvent;
+import org.apache.maven.surefire.eventapi.ConsoleWarningEvent;
+import org.apache.maven.surefire.eventapi.ControlByeEvent;
+import org.apache.maven.surefire.eventapi.ControlNextTestEvent;
+import org.apache.maven.surefire.eventapi.ControlStopOnNextTestEvent;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.eventapi.StandardStreamErrEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamErrWithNewLineEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamOutEvent;
+import org.apache.maven.surefire.eventapi.StandardStreamOutWithNewLineEvent;
+import org.apache.maven.surefire.eventapi.SystemPropertyEvent;
+import org.apache.maven.surefire.eventapi.TestAssumptionFailureEvent;
+import org.apache.maven.surefire.eventapi.TestErrorEvent;
+import org.apache.maven.surefire.eventapi.TestFailedEvent;
+import org.apache.maven.surefire.eventapi.TestSkippedEvent;
+import org.apache.maven.surefire.eventapi.TestStartingEvent;
+import org.apache.maven.surefire.eventapi.TestSucceededEvent;
+import org.apache.maven.surefire.eventapi.TestsetCompletedEvent;
+import org.apache.maven.surefire.eventapi.TestsetStartingEvent;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
import org.junit.Test;
+import javax.annotation.Nonnull;
+import java.io.ByteArrayInputStream;
+import java.io.Closeable;
import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.nio.channels.ReadableByteChannel;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import static java.nio.channels.Channels.newChannel;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Arrays.copyOfRange;
import static org.apache.commons.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_DEBUG;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_ERR;
-import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_WARN;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_INFO;
+import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_WARN;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.SET_COMPLETED;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.SET_STARTING;
-import static org.apache.maven.plugin.surefire.booterclient.MockReporter.STDOUT;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.STDERR;
+import static org.apache.maven.plugin.surefire.booterclient.MockReporter.STDOUT;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_ASSUMPTION_FAIL;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_ERROR;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_FAILED;
-import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_STARTING;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_SKIPPED;
+import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_STARTING;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.TEST_SUCCEEDED;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_ERROR;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.MapAssert.entry;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.startsWith;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -74,204 +106,74 @@ public class ForkClientTest
{
private static final int ELAPSED_TIME = 102;
- @Test
- public void shouldNotFailOnEmptyInput1()
+ @Test( expected = NullPointerException.class )
+ public void shouldFailOnNPE()
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
when( factory.getReportsDirectory() )
.thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeLine( null );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
+ ForkClient client = new ForkClient( factory, null, 0 );
+ client.handleEvent( null );
}
@Test
- public void shouldNotFailOnEmptyInput2()
+ public void shouldLogJvmMessage() throws Exception
{
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
+ String nativeStream = "Listening for transport dt_socket at address: bla";
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeLine( " " );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
- }
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( nativeStream.getBytes() ) );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
- @Test
- public void shouldNotFailOnEmptyInput3()
- throws IOException
- {
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( null );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
- }
+ countdown.awaitClosed();
- @Test
- public void shouldNotFailOnEmptyInput4()
- throws IOException
- {
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- when( logger.isDebugEnabled() )
- .thenReturn( true );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( " " );
- verify( logger )
- .isDebugEnabled();
- verify( logger )
- .warning( startsWith( "Corrupted STDOUT by directly writing to native stream in forked JVM 0. "
- + "See FAQ web page and the dump file " ) );
- verify( logger )
- .debug( " " );
- verifyNoMoreInteractions( logger );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
- }
+ verify( logger )
+ .info( "Listening for transport dt_socket at address: bla" );
+ }
+
+ assertThat( eventHandler.sizeOfEventCache() )
+ .isEqualTo( 0 );
- @Test
- public void shouldNotFailOnEmptyInput5()
- throws IOException
- {
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- when( logger.isDebugEnabled() )
- .thenReturn( true );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( "Listening for transport dt_socket at address: bla" );
- verify( logger )
- .isDebugEnabled();
- verify( logger )
- .debug( "Listening for transport dt_socket at address: bla" );
verifyNoMoreInteractions( logger );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
}
@Test
- public void shouldNotFailOnEmptyInput6()
- throws IOException
+ public void shouldLogJvmMessageAndProcessEvent() throws Exception
{
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
+ String nativeStream = "Listening for transport dt_socket at address: bla\n:maven-surefire-event:bye:\n";
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
ConsoleLogger logger = mock( ConsoleLogger.class );
when( logger.isDebugEnabled() )
- .thenReturn( false );
+ .thenReturn( false );
when( logger.isInfoEnabled() )
- .thenReturn( true );
- ForkClient client = new ForkClient( factory, null, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( "Listening for transport dt_socket at address: bla" );
- verify( logger )
- .isDebugEnabled();
- verify( logger )
- .isInfoEnabled();
- verify( logger )
+ .thenReturn( true );
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( nativeStream.getBytes() ) );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+
+ Event event = eventHandler.pullEvent();
+ assertThat( event.isControlCategory() )
+ .isTrue();
+ assertThat( event.getEventType() )
+ .isEqualTo( BOOTERCODE_BYE );
+
+ verify( logger )
.info( "Listening for transport dt_socket at address: bla" );
+
+ countdown.awaitClosed();
+ }
+
+ assertThat( eventHandler.sizeOfEventCache() )
+ .isEqualTo( 0 );
+
verifyNoMoreInteractions( logger );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.getErrorInFork() )
- .isNull();
- assertThat( client.isErrorInFork() )
- .isFalse();
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
}
@Test
@@ -279,7 +181,7 @@ public class ForkClientTest
{
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- ForkClient client = new ForkClient( null, notifiableTestStream, null, null, 0 );
+ ForkClient client = new ForkClient( null, notifiableTestStream, 0 );
client.kill();
verify( notifiableTestStream, times( 1 ) )
@@ -288,7 +190,6 @@ public class ForkClientTest
@Test
public void shouldAcquireNextTest()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -296,10 +197,8 @@ public class ForkClientTest
when( factory.getReportsDirectory() )
.thenReturn( new File( target, "surefire-reports" ) );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:next-test\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new ControlNextTestEvent() );
verify( notifiableTestStream, times( 1 ) )
.provideNewTest();
verifyNoMoreInteractions( notifiableTestStream );
@@ -322,7 +221,6 @@ public class ForkClientTest
@Test
public void shouldNotifyWithBye()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -330,11 +228,9 @@ public class ForkClientTest
when( factory.getReportsDirectory() )
.thenReturn( new File( target, "surefire-reports" ) );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:bye\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new ControlByeEvent() );
client.kill();
verify( notifiableTestStream, times( 1 ) )
@@ -361,7 +257,6 @@ public class ForkClientTest
@Test
public void shouldStopOnNextTest()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -369,10 +264,8 @@ public class ForkClientTest
when( factory.getReportsDirectory() )
.thenReturn( new File( target, "surefire-reports" ) );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
final boolean[] verified = {false};
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 )
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 )
{
@Override
protected void stopOnNextTest()
@@ -381,7 +274,7 @@ public class ForkClientTest
verified[0] = true;
}
};
- client.consumeMultiLineContent( ":maven:surefire:std:out:stop-on-next-test\n" );
+ client.handleEvent( new ControlStopOnNextTestEvent() );
verifyZeroInteractions( notifiableTestStream );
verifyZeroInteractions( factory );
assertThat( verified[0] )
@@ -404,7 +297,6 @@ public class ForkClientTest
@Test
public void shouldReceiveStdOut()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -415,10 +307,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:std-out-stream:normal-run:UTF-8:bXNn\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new StandardStreamOutEvent( NORMAL_RUN, "msg" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -449,7 +339,6 @@ public class ForkClientTest
@Test
public void shouldReceiveStdOutNewLine()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -460,10 +349,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:std-out-stream-new-line:normal-run:UTF-8:bXNn\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new StandardStreamOutWithNewLineEvent( NORMAL_RUN, "msg" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -494,7 +381,6 @@ public class ForkClientTest
@Test
public void shouldReceiveStdErr()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -505,10 +391,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:std-err-stream:normal-run:UTF-8:bXNn\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new StandardStreamErrEvent( NORMAL_RUN, "msg" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -539,7 +423,6 @@ public class ForkClientTest
@Test
public void shouldReceiveStdErrNewLine()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -550,10 +433,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:std-err-stream-new-line:normal-run:UTF-8:bXNn\n" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new StandardStreamErrWithNewLineEvent( NORMAL_RUN, "msg" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -584,28 +465,22 @@ public class ForkClientTest
@Test
public void shouldLogConsoleError()
- throws IOException
{
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
MockReporter receiver = new MockReporter();
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:console-error-log:UTF-8:"
- + encodeBase64String( "Listening for transport dt_socket at address:".getBytes( UTF_8 ) )
- + ":-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ StackTraceWriter stackTrace =
+ new DeserializedStacktraceWriter( "Listening for transport dt_socket at address: 5005", null, null );
+ Event event = new ConsoleErrorEvent( stackTrace );
+ client.handleEvent( event );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
verify( factory, times( 1 ) )
- .getReportsDirectory();
+ .getReportsDirectory();
verifyNoMoreInteractions( factory );
assertThat( client.getReporter() )
.isNotNull();
@@ -616,7 +491,7 @@ public class ForkClientTest
assertThat( receiver.getData() )
.isNotEmpty();
assertThat( receiver.getData() )
- .contains( "Listening for transport dt_socket at address:" );
+ .contains( "Listening for transport dt_socket at address: 5005" );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -634,66 +509,51 @@ public class ForkClientTest
}
@Test
- public void shouldLogConsoleErrorWithStackTrace()
- throws IOException
+ public void shouldLogConsoleErrorWithStackTrace() throws Exception
{
- String cwd = System.getProperty( "user.dir" );
- File target = new File( cwd, "target" );
- DefaultReporterFactory factory = mock( DefaultReporterFactory.class );
- when( factory.getReportsDirectory() )
- .thenReturn( new File( target, "surefire-reports" ) );
- MockReporter receiver = new MockReporter();
- when( factory.createReporter() )
- .thenReturn( receiver );
- NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
+ String nativeStream = ":maven-surefire-event:console-error-log:UTF-8"
+ + ":" + encodeBase64String( "Listening for transport dt_socket at address: 5005".getBytes( UTF_8 ) )
+ + ":" + encodeBase64String( "s1".getBytes( UTF_8 ) )
+ + ":" + encodeBase64String( "s2".getBytes( UTF_8 ) ) + ":";
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:console-error-log:UTF-8"
- + ":" + encodeBase64String( "Listening for transport dt_socket at address:".getBytes( UTF_8 ) )
- + ":" + encodeBase64String( "s1".getBytes( UTF_8 ) )
- + ":" + encodeBase64String( "s2".getBytes( UTF_8 ) ) );
- verifyZeroInteractions( notifiableTestStream );
- verify( factory, times( 1 ) )
- .createReporter();
- verify( factory, times( 1 ) )
- .getReportsDirectory();
- verifyNoMoreInteractions( factory );
- assertThat( client.getReporter() )
- .isNotNull();
- assertThat( receiver.getEvents() )
- .isNotEmpty();
- assertThat( receiver.getEvents() )
- .contains( CONSOLE_ERR );
- assertThat( receiver.getData() )
- .isNotEmpty();
- assertThat( receiver.getData() )
- .contains( "Listening for transport dt_socket at address:" );
- assertThat( client.isSaidGoodBye() )
- .isFalse();
- assertThat( client.isErrorInFork() )
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( nativeStream.getBytes() ) );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+
+ Event event = eventHandler.pullEvent();
+ assertThat( event.isConsoleErrorCategory() )
.isTrue();
- assertThat( client.getErrorInFork() )
+ assertThat( event.isConsoleCategory() )
+ .isTrue();
+ assertThat( event.getEventType() )
+ .isEqualTo( BOOTERCODE_CONSOLE_ERROR );
+
+ ConsoleErrorEvent consoleEvent = (ConsoleErrorEvent) event;
+ assertThat( consoleEvent.getStackTraceWriter() )
.isNotNull();
- assertThat( client.getErrorInFork().getThrowable().getLocalizedMessage() )
- .isEqualTo( "Listening for transport dt_socket at address:" );
- assertThat( client.getErrorInFork().smartTrimmedStackTrace() )
+ assertThat( consoleEvent.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( "Listening for transport dt_socket at address: 5005" );
+ assertThat( consoleEvent.getStackTraceWriter().smartTrimmedStackTrace() )
.isEqualTo( "s1" );
- assertThat( client.getErrorInFork().writeTrimmedTraceToString() )
+ assertThat( consoleEvent.getStackTraceWriter().writeTraceToString() )
.isEqualTo( "s2" );
- assertThat( client.hadTimeout() )
- .isFalse();
- assertThat( client.hasTestsInProgress() )
- .isFalse();
- assertThat( client.testsInProgress() )
- .isEmpty();
- assertThat( client.getTestVmSystemProperties() )
- .isEmpty();
+
+ countdown.awaitClosed();
+
+ verifyZeroInteractions( logger );
+ }
+
+ assertThat( eventHandler.sizeOfEventCache() )
+ .isEqualTo( 0 );
+
+ verifyNoMoreInteractions( logger );
}
@Test
public void shouldLogConsoleWarning()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -704,13 +564,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- when( logger.isWarnEnabled() )
- .thenReturn( true );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:console-warning-log:UTF-8:"
- + encodeBase64String( "s1".getBytes( UTF_8 ) ) );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new ConsoleWarningEvent( "s1" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -741,7 +596,6 @@ public class ForkClientTest
@Test
public void shouldLogConsoleDebug()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -752,13 +606,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- when( logger.isDebugEnabled() )
- .thenReturn( true );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:console-debug-log:UTF-8:"
- + encodeBase64String( "s1".getBytes( UTF_8 ) ) );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new ConsoleDebugEvent( "s1" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -789,7 +638,6 @@ public class ForkClientTest
@Test
public void shouldLogConsoleInfo()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -800,11 +648,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:console-info-log:UTF-8:"
- + encodeBase64String( "s1".getBytes( UTF_8 ) ) );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new ConsoleInfoEvent( "s1" ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory, times( 1 ) )
.createReporter();
@@ -835,7 +680,6 @@ public class ForkClientTest
@Test
public void shouldSendSystemProperty()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -846,11 +690,8 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:sys-prop:normal-run:UTF-8:azE=:djE="
- + encodeBase64String( "s1".getBytes( UTF_8 ) ) );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new SystemPropertyEvent( NORMAL_RUN, "k1", "v1" ) );
verifyZeroInteractions( notifiableTestStream );
verifyZeroInteractions( factory );
assertThat( client.getReporter() )
@@ -879,7 +720,6 @@ public class ForkClientTest
@Test
public void shouldSendTestsetStartingKilled()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -890,21 +730,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -913,7 +743,7 @@ public class ForkClientTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
- ReportEntry reportEntry = mock( ReportEntry.class );
+ TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
when( reportEntry.getGroup() ).thenReturn( "this group" );
when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -922,33 +752,8 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:testset-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new TestsetStartingEvent( NORMAL_RUN, reportEntry ) );
client.tryToTimeout( System.currentTimeMillis() + 1000L, 1 );
@@ -983,13 +788,13 @@ public class ForkClientTest
.isNotNull();
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) )
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
- .isEqualTo( "msg" );
+ .isEqualTo( exceptionMessage );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1010,7 +815,6 @@ public class ForkClientTest
@Test
public void shouldSendTestsetStarting()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1021,21 +825,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1044,7 +838,7 @@ public class ForkClientTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
- ReportEntry reportEntry = mock( ReportEntry.class );
+ TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
when( reportEntry.getGroup() ).thenReturn( "this group" );
when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1055,36 +849,8 @@ public class ForkClientTest
when( reportEntry.getSourceText() ).thenReturn( "dn1" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedNameText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:testset-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + encodedSourceText
- + ":"
- + encodedName
- + ":"
- + encodedNameText
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
-
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new TestsetStartingEvent( NORMAL_RUN, reportEntry ) );
client.tryToTimeout( System.currentTimeMillis(), 1 );
verifyZeroInteractions( notifiableTestStream );
@@ -1118,11 +884,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1145,7 +911,6 @@ public class ForkClientTest
@Test
public void shouldSendTestsetCompleted()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1156,21 +921,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1179,7 +934,7 @@ public class ForkClientTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
- ReportEntry reportEntry = mock( ReportEntry.class );
+ TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
when( reportEntry.getGroup() ).thenReturn( "this group" );
when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1188,33 +943,8 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:testset-completed:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new TestsetCompletedEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1249,9 +979,9 @@ public class ForkClientTest
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
.isEqualTo( "MyTest:86 >> Error" );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1274,7 +1004,6 @@ public class ForkClientTest
@Test
public void shouldSendTestStarting()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1285,21 +1014,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1317,33 +1036,8 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1381,11 +1075,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1404,7 +1098,6 @@ public class ForkClientTest
@Test
public void shouldSendTestSucceeded()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1415,21 +1108,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1447,42 +1130,15 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
-
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":-:-:-:-:-:-:-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ SimpleReportEntry testStarted = new SimpleReportEntry( reportEntry.getSourceName(), null, null, null );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
assertThat( client.testsInProgress() )
.hasSize( 1 )
.contains( "pkg.MyTest" );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-succeeded:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace );
+ client.handleEvent( new TestSucceededEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1519,11 +1175,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1546,7 +1202,6 @@ public class ForkClientTest
@Test
public void shouldSendTestFailed()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1557,21 +1212,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1589,42 +1234,15 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
-
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":-:-:-:-:-:-:-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ SimpleReportEntry testClass = new SimpleReportEntry( reportEntry.getSourceName(), null, null, null );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, testClass ) );
assertThat( client.testsInProgress() )
.hasSize( 1 )
.contains( "pkg.MyTest" );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-failed:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
+ client.handleEvent( new TestFailedEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1645,6 +1263,8 @@ public class ForkClientTest
.isNull();
assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getNameText() )
.isNull();
+ assertThat( ( (ReportEntry) receiver.getData().get( 0 ) ).getStackTraceWriter() )
+ .isNull();
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getSourceName() )
.isEqualTo( "pkg.MyTest" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getSourceText() )
@@ -1667,9 +1287,9 @@ public class ForkClientTest
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
.isEqualTo( "MyTest:86 >> Error" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1692,7 +1312,6 @@ public class ForkClientTest
@Test
public void shouldSendTestSkipped()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1703,21 +1322,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1735,42 +1344,15 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
-
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":-:-:-:-:-:-:-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ SimpleReportEntry testStarted = new SimpleReportEntry( reportEntry.getSourceName(), null, null, null );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
assertThat( client.testsInProgress() )
.hasSize( 1 )
.contains( "pkg.MyTest" );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-skipped:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace );
+ client.handleEvent( new TestSkippedEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1811,11 +1393,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1838,7 +1420,6 @@ public class ForkClientTest
@Test
public void shouldSendTestError()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1849,21 +1430,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -1882,45 +1453,16 @@ public class ForkClientTest
when( reportEntry.getSourceText() ).thenReturn( "display name" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
-
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + encodedSourceText
- + ":-:':-:-:-:-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ SimpleReportEntry testStarted =
+ new SimpleReportEntry( reportEntry.getSourceName(), reportEntry.getSourceText(), null, null );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
assertThat( client.testsInProgress() )
.hasSize( 1 )
.contains( "pkg.MyTest" );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-error:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + encodedSourceText
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace );
+ client.handleEvent( new TestErrorEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -1957,11 +1499,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -1984,7 +1526,6 @@ public class ForkClientTest
@Test
public void shouldSendTestAssumptionFailure()
- throws IOException
{
String cwd = System.getProperty( "user.dir" );
File target = new File( cwd, "target" );
@@ -1995,21 +1536,11 @@ public class ForkClientTest
when( factory.createReporter() )
.thenReturn( receiver );
NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
- AtomicBoolean printedErrorStream = new AtomicBoolean();
- ConsoleLogger logger = mock( ConsoleLogger.class );
-
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -2028,43 +1559,15 @@ public class ForkClientTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ForkClient client = new ForkClient( factory, notifiableTestStream, logger, printedErrorStream, 0 );
-
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":-:-:-:-:-:-:-:-:-" );
+ ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
+ SimpleReportEntry testStarted = new SimpleReportEntry( reportEntry.getSourceName(), null, null, null );
+ client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
assertThat( client.testsInProgress() )
.hasSize( 1 )
.contains( "pkg.MyTest" );
- client.consumeMultiLineContent( ":maven:surefire:std:out:test-assumption-failure:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + encodedText
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace );
+ client.handleEvent( new TestAssumptionFailureEvent( NORMAL_RUN, reportEntry ) );
verifyZeroInteractions( notifiableTestStream );
verify( factory ).createReporter();
@@ -2101,11 +1604,11 @@ public class ForkClientTest
.getStackTraceWriter().getThrowable().getLocalizedMessage() )
.isEqualTo( "msg" );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( "MyTest:86 >> Error" );
+ .isEqualTo( smartStackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( stackTrace );
assertThat( ( (ReportEntry) receiver.getData().get( 1 ) ).getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( "trace line 1\ntrace line 2" );
+ .isEqualTo( trimmedStackTrace );
assertThat( client.isSaidGoodBye() )
.isFalse();
assertThat( client.isErrorInFork() )
@@ -2126,9 +1629,24 @@ public class ForkClientTest
.isSameAs( factory );
}
- private static byte[] toArray( ByteBuffer buffer )
+ private static class EH implements EventHandler<Event>
{
- return copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
- }
+ private final BlockingQueue<Event> cache = new LinkedBlockingQueue<>( 1 );
+
+ Event pullEvent() throws InterruptedException
+ {
+ return cache.poll( 1, TimeUnit.MINUTES );
+ }
+ int sizeOfEventCache()
+ {
+ return cache.size();
+ }
+
+ @Override
+ public void handleEvent( @Nonnull Event event )
+ {
+ cache.add( event );
+ }
+ }
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
deleted file mode 100644
index 9b0d9c9..0000000
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
+++ /dev/null
@@ -1,901 +0,0 @@
-package org.apache.maven.plugin.surefire.booterclient.output;
-
-/*
- * 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.ConsoleLoggerUtils;
-import org.apache.maven.surefire.booter.ForkedChannelEncoder;
-import org.apache.maven.surefire.report.ReportEntry;
-import org.apache.maven.surefire.report.RunMode;
-import org.apache.maven.surefire.report.SafeThrowable;
-import org.apache.maven.surefire.report.StackTraceWriter;
-import org.apache.maven.surefire.util.internal.ObjectUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.FromDataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.PrintStream;
-import java.io.StringReader;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Map;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.codec.binary.Base64.encodeBase64String;
-import static org.apache.maven.plugin.surefire.booterclient.output.ForkedChannelDecoder.toReportEntry;
-import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.rules.ExpectedException.none;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.nullable;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-/**
- * Test for {@link ForkedChannelDecoder}.
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M4
- */
-@RunWith( Enclosed.class )
-public class ForkedChannelDecoderTest
-{
- /**
- *
- */
- public static class DecoderOperationsTest
- {
- @Rule
- public final ExpectedException rule = none();
-
- @Test
- public void shouldBeFailSafe()
- {
- assertThat( ForkedChannelDecoder.decode( null, UTF_8 ) ).isNull();
- assertThat( ForkedChannelDecoder.decode( "-", UTF_8 ) ).isNull();
- assertThat( ForkedChannelDecoder.decodeToInteger( null ) ).isNull();
- assertThat( ForkedChannelDecoder.decodeToInteger( "-" ) ).isNull();
- }
-
- @Test
- @SuppressWarnings( "checkstyle:innerassignment" )
- public void shouldHaveSystemProperty() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.sendSystemProperties( ObjectUtils.systemProps() );
-
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
- LineNumberReader reader = out.newReader( UTF_8 );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- for ( String line; ( line = reader.readLine() ) != null; )
- {
- decoder.handleEvent( line, errorHandler );
- }
- verifyZeroInteractions( errorHandler );
- assertThat( reader.getLineNumber() ).isPositive();
- }
-
- @Test
- public void shouldRecognizeEmptyStream4ReportEntry()
- {
- ReportEntry reportEntry = toReportEntry( null, null, null, "", "", null, null, "",
- "", "", null );
- assertThat( reportEntry ).isNull();
-
- reportEntry = toReportEntry( UTF_8, "", "", "", "", "", "", "-", "", "", "" );
- assertThat( reportEntry ).isNotNull();
- assertThat( reportEntry.getStackTraceWriter() ).isNull();
- assertThat( reportEntry.getSourceName() ).isEmpty();
- assertThat( reportEntry.getSourceText() ).isEmpty();
- assertThat( reportEntry.getName() ).isEmpty();
- assertThat( reportEntry.getNameText() ).isEmpty();
- assertThat( reportEntry.getGroup() ).isEmpty();
- assertThat( reportEntry.getNameWithGroup() ).isEmpty();
- assertThat( reportEntry.getMessage() ).isEmpty();
- assertThat( reportEntry.getElapsed() ).isNull();
-
- rule.expect( NumberFormatException.class );
- toReportEntry( UTF_8, "", "", "", "", "", "", "", "", "", "" );
- fail();
- }
-
- @Test
- @SuppressWarnings( "checkstyle:magicnumber" )
- public void testCreatingReportEntry()
- {
- final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
- final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
- final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
- final String trimmedStackTrace = "trace line 1\ntrace line 2";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
-
- SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
- StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
- when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
- when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
- when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
- when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
-
- ReportEntry reportEntry = mock( ReportEntry.class );
- when( reportEntry.getElapsed() ).thenReturn( 102 );
- when( reportEntry.getGroup() ).thenReturn( "this group" );
- when( reportEntry.getMessage() ).thenReturn( "skipped test" );
- when( reportEntry.getName() ).thenReturn( "my test" );
- when( reportEntry.getNameText() ).thenReturn( "my display name" );
- when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
- when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
- when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
- when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
-
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ReportEntry decodedReportEntry = toReportEntry( UTF_8, encodedSourceName, encodedSourceText,
- encodedName, encodedText, encodedGroup, encodedMessage, "-", null, null, null );
-
- assertThat( decodedReportEntry ).isNotNull();
- assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
- assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
- assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
- assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
- assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
- assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
- assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
-
- decodedReportEntry = toReportEntry( UTF_8, encodedSourceName, encodedSourceText, encodedName, encodedText,
- encodedGroup, encodedMessage, "-", encodedExceptionMsg, encodedSmartStackTrace, null );
-
- assertThat( decodedReportEntry ).isNotNull();
- assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
- assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
- assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
- assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
- assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
- assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
- assertThat( decodedReportEntry.getElapsed() ).isNull();
- assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
-
- decodedReportEntry = toReportEntry( UTF_8, encodedSourceName, encodedSourceText, encodedName, encodedText,
- encodedGroup, encodedMessage, "1003", encodedExceptionMsg, encodedSmartStackTrace, null );
-
- assertThat( decodedReportEntry ).isNotNull();
- assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
- assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
- assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
- assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
- assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
- assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
- assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
- assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
-
- decodedReportEntry = toReportEntry( UTF_8, encodedSourceName, encodedSourceText, encodedName, encodedText,
- encodedGroup, encodedMessage, "1003", encodedExceptionMsg, encodedSmartStackTrace,
- encodedStackTrace );
-
- assertThat( decodedReportEntry ).isNotNull();
- assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
- assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
- assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
- assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
- assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
- assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
- assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
- assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
- assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
- assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
- .isEqualTo( exceptionMessage );
- assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( smartStackTrace );
- assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
- assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
-
- decodedReportEntry = toReportEntry( UTF_8, encodedSourceName, encodedSourceText, encodedName, encodedText,
- encodedGroup, encodedMessage, "1003", encodedExceptionMsg, encodedSmartStackTrace,
- encodedTrimmedStackTrace );
-
- assertThat( decodedReportEntry ).isNotNull();
- assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
- assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
- assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
- assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
- assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
- assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
- assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
- assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
- assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
- assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
- .isEqualTo( exceptionMessage );
- assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( smartStackTrace );
- assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( trimmedStackTrace );
- assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() )
- .isEqualTo( trimmedStackTrace );
- }
-
- @Test
- public void shouldSendByeEvent() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.bye();
- String read = new String( out.toByteArray(), UTF_8 );
- assertThat( read )
- .isEqualTo( ":maven:surefire:std:out:bye\n" );
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setByeListener( new EventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void shouldSendStopOnNextTestEvent() throws IOException
- {
-
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stopOnNextTest();
- String read = new String( out.toByteArray(), UTF_8 );
- assertThat( read )
- .isEqualTo( ":maven:surefire:std:out:stop-on-next-test\n" );
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStopOnNextTestListener( new EventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void shouldCorrectlyDecodeStackTracesWithEmptyStringTraceMessages()
- {
- String exceptionMessage = "";
- String smartStackTrace = "JUnit5Test.failWithEmptyString:16";
- String exceptionStackTrace = "org.opentest4j.AssertionFailedError: \n"
- + "\tat JUnit5Test.failWithEmptyString(JUnit5Test.java:16)\n";
-
- StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
- SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
- when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
- when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
- when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
- when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
-
- ReportEntry reportEntry = mock( ReportEntry.class );
- when( reportEntry.getElapsed() ).thenReturn( 7 );
- when( reportEntry.getGroup() ).thenReturn( null );
- when( reportEntry.getMessage() ).thenReturn( null );
- when( reportEntry.getName() ).thenReturn( "failWithEmptyString" );
- when( reportEntry.getNameWithGroup() ).thenReturn( "JUnit5Test" );
- when( reportEntry.getSourceName() ).thenReturn( "JUnit5Test" );
- when( reportEntry.getSourceText() ).thenReturn( null );
- when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
-
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.testFailed( reportEntry, true );
- String line = new String( out.toByteArray(), UTF_8 );
-
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setTestFailedListener( new ReportEventAssertionListener( reportEntry ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( line, errorHandler );
- verifyZeroInteractions( errorHandler );
- }
-
- @Test
- public void shouldSendNextTestEvent() throws IOException
- {
-
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.acquireNextTest();
- String read = new String( out.toByteArray(), UTF_8 );
- assertThat( read )
- .isEqualTo( ":maven:surefire:std:out:next-test\n" );
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setAcquireNextTestListener( new EventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testConsole() throws IOException
- {
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.consoleInfoLog( "msg" );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setConsoleInfoListener( new StringEventAssertionListener( "msg" ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testError() throws IOException
- {
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.consoleErrorLog( "msg" );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setConsoleErrorListener( new StackTraceEventListener( "msg", null, null ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testErrorWithException() throws IOException
- {
- Throwable t = new Throwable( "msg" );
-
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.consoleErrorLog( t );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- String stackTrace = ConsoleLoggerUtils.toString( t );
- decoder.setConsoleErrorListener( new StackTraceEventListener( "msg", null, stackTrace ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testErrorWithStackTraceWriter() throws IOException
- {
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "1", "2", "3" );
- forkedChannelEncoder.consoleErrorLog( stackTraceWriter, false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setConsoleErrorListener( new StackTraceEventListener( "1", "2", "3" ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testDebug() throws IOException
- {
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.consoleDebugLog( "msg" );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setConsoleDebugListener( new StringEventAssertionListener( "msg" ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testWarning() throws IOException
- {
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.consoleWarningLog( "msg" );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setConsoleWarningListener( new StringEventAssertionListener( "msg" ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdOutStream() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdOut( "msg", false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdOutListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdOutStreamPrint() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdOut( "", false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdOutListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, "", false ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdOutStreamPrintWithNull() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdOut( null, false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdOutListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, null, false ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdOutStreamPrintln() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdOut( "", true );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdOutListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, "", true ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdOutStreamPrintlnWithNull() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdOut( null, true );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdOutListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, null, true ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void testStdErrStream() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.stdErr( "msg", false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setStdErrListener( new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false ) );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- assertThat( lines.readLine() )
- .isNull();
- }
-
- @Test
- public void shouldCountSameNumberOfSystemProperties() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- forkedChannelEncoder.sendSystemProperties( ObjectUtils.systemProps() );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- }
-
- @Test
- public void shouldHandleErrorAfterNullLine()
- {
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( null, errorHandler );
- verify( errorHandler, times( 1 ) )
- .handledError( nullable( String.class ), nullable( Throwable.class ) );
- }
-
- @Test
- public void shouldHandleErrorAfterUnknownOperation()
- {
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( ":maven:surefire:std:out:abnormal-run:-", errorHandler );
- verify( errorHandler, times( 1 ) )
- .handledError( eq( ":maven:surefire:std:out:abnormal-run:-" ), nullable( Throwable.class ) );
- }
-
- @Test
- public void shouldHandleExit() throws IOException
- {
- Stream out = Stream.newStream();
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
- StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
- when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
- when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
- when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
- when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
- forkedChannelEncoder.sendExitEvent( stackTraceWriter, false );
-
- LineNumberReader lines = out.newReader( UTF_8 );
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
- decoder.setExitErrorEventListener( new ForkedProcessExitErrorListener()
- {
- @Override
- public void handle( String exceptionMessage, String smartTrimmedStackTrace, String stackTrace )
- {
- assertThat( exceptionMessage ).isEqualTo( "1" );
- assertThat( smartTrimmedStackTrace ).isEqualTo( "2" );
- assertThat( stackTrace ).isEqualTo( "3" );
- }
- } );
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( lines.readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- }
- }
-
- /**
- *
- */
- @RunWith( Theories.class )
- public static class ReportEntryTest
- {
- @DataPoints( value = "operation" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static String[][] operations = { { "testSetStarting", "setTestSetStartingListener" },
- { "testSetCompleted", "setTestSetCompletedListener" },
- { "testStarting", "setTestStartingListener" },
- { "testSucceeded", "setTestSucceededListener" },
- { "testFailed", "setTestFailedListener" },
- { "testSkipped", "setTestSkippedListener" },
- { "testError", "setTestErrorListener" },
- { "testAssumptionFailure", "setTestAssumptionFailureListener" }
- };
-
- @DataPoints( value = "reportedMessage" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static String[] reportedMessage = { null, "skipped test" };
-
- @DataPoints( value = "elapsed" )
- @SuppressWarnings( { "checkstyle:visibilitymodifier", "checkstyle:magicnumber" } )
- public static Integer[] elapsed = { null, 102 };
-
- @DataPoints( value = "trim" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static boolean[] trim = { false, true };
-
- @DataPoints( value = "msg" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static boolean[] msg = { false, true };
-
- @DataPoints( value = "smart" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static boolean[] smart = { false, true };
-
- @DataPoints( value = "trace" )
- @SuppressWarnings( "checkstyle:visibilitymodifier" )
- public static boolean[] trace = { false, true };
-
- @Theory
- public void testReportEntryOperations( @FromDataPoints( "operation" ) String[] operation,
- @FromDataPoints( "reportedMessage" ) String reportedMessage,
- @FromDataPoints( "elapsed" ) Integer elapsed,
- @FromDataPoints( "trim" ) boolean trim,
- @FromDataPoints( "msg" ) boolean msg,
- @FromDataPoints( "smart" ) boolean smart,
- @FromDataPoints( "trace" ) boolean trace )
- throws Exception
- {
- String exceptionMessage = msg ? "msg" : null;
- String smartStackTrace = smart ? "MyTest:86 >> Error" : null;
- String exceptionStackTrace =
- trace ? ( trim ? "trace line 1\ntrace line 2" : "Exception: msg\ntrace line 1\ntrace line 2" )
- : null;
-
- StackTraceWriter stackTraceWriter = null;
- if ( exceptionStackTrace != null )
- {
- SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
- stackTraceWriter = mock( StackTraceWriter.class );
- when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
- when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
- when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
- when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
- }
-
- ReportEntry reportEntry = mock( ReportEntry.class );
- when( reportEntry.getElapsed() ).thenReturn( elapsed );
- when( reportEntry.getGroup() ).thenReturn( "this group" );
- when( reportEntry.getMessage() ).thenReturn( reportedMessage );
- when( reportEntry.getName() ).thenReturn( "my test" );
- when( reportEntry.getName() ).thenReturn( "display name of test" );
- when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
- when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
- when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
- when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
-
- Stream out = Stream.newStream();
-
- ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( out );
-
- ForkedChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
- .invoke( forkedChannelEncoder, reportEntry, trim );
-
- ForkedChannelDecoder decoder = new ForkedChannelDecoder();
-
- ForkedChannelDecoder.class.getMethod( operation[1], ForkedProcessReportEventListener.class )
- .invoke( decoder, new ReportEventAssertionListener( reportEntry ) );
-
- AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
- decoder.handleEvent( out.newReader( UTF_8 ).readLine(), errorHandler );
- verifyZeroInteractions( errorHandler );
- }
- }
-
- private static class AssertionErrorHandler implements ForkedChannelDecoderErrorHandler
- {
- public void handledError( String line, Throwable e )
- {
- if ( e != null )
- {
- e.printStackTrace();
- }
- fail( line + ( e == null ? "" : "\n" + e.getLocalizedMessage() ) );
- }
- }
-
- private static class PropertyEventAssertionListener implements ForkedProcessPropertyEventListener
- {
- private final Map sysProps = System.getProperties();
-
- public void handle( RunMode runMode, String key, String value )
- {
- assertThat( runMode ).isEqualTo( NORMAL_RUN );
- assertTrue( sysProps.containsKey( key ) );
- assertThat( sysProps.get( key ) ).isEqualTo( value );
- }
- }
-
- private static class EventAssertionListener implements ForkedProcessEventListener
- {
- public void handle()
- {
- }
- }
-
- private static class StringEventAssertionListener implements ForkedProcessStringEventListener
- {
- private final String msg;
-
- StringEventAssertionListener( String msg )
- {
- this.msg = msg;
- }
-
- public void handle( String msg )
- {
- assertThat( msg )
- .isEqualTo( this.msg );
- }
- }
-
- private static class StackTraceEventListener implements ForkedProcessStackTraceEventListener
- {
- private final String msg;
- private final String smartStackTrace;
- private final String stackTrace;
-
- StackTraceEventListener( String msg, String smartStackTrace, String stackTrace )
- {
- this.msg = msg;
- this.smartStackTrace = smartStackTrace;
- this.stackTrace = stackTrace;
- }
-
- @Override
- public void handle( String msg, String smartStackTrace, String stackTrace )
- {
- assertThat( msg )
- .isEqualTo( this.msg );
-
- assertThat( smartStackTrace )
- .isEqualTo( this.smartStackTrace );
-
- assertThat( stackTrace )
- .isEqualTo( this.stackTrace );
- }
- }
-
- private static class StandardOutErrEventAssertionListener implements ForkedProcessStandardOutErrEventListener
- {
- private final RunMode runMode;
- private final String output;
- private final boolean newLine;
-
- StandardOutErrEventAssertionListener( RunMode runMode, String output, boolean newLine )
- {
- this.runMode = runMode;
- this.output = output;
- this.newLine = newLine;
- }
-
- public void handle( RunMode runMode, String output, boolean newLine )
- {
- assertThat( runMode )
- .isEqualTo( this.runMode );
-
- assertThat( output )
- .isEqualTo( this.output );
-
- assertThat( newLine )
- .isEqualTo( this.newLine );
- }
- }
-
- private static class ReportEventAssertionListener implements ForkedProcessReportEventListener
- {
- private final ReportEntry reportEntry;
-
- ReportEventAssertionListener( ReportEntry reportEntry )
- {
- this.reportEntry = reportEntry;
- }
-
- public void handle( RunMode runMode, ReportEntry reportEntry )
- {
- assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
- assertThat( reportEntry.getSourceText() ).isEqualTo( this.reportEntry.getSourceText() );
- assertThat( reportEntry.getName() ).isEqualTo( this.reportEntry.getName() );
- assertThat( reportEntry.getNameText() ).isEqualTo( this.reportEntry.getNameText() );
- assertThat( reportEntry.getGroup() ).isEqualTo( this.reportEntry.getGroup() );
- assertThat( reportEntry.getMessage() ).isEqualTo( this.reportEntry.getMessage() );
- assertThat( reportEntry.getElapsed() ).isEqualTo( this.reportEntry.getElapsed() );
- if ( reportEntry.getStackTraceWriter() == null )
- {
- assertThat( this.reportEntry.getStackTraceWriter() ).isNull();
- }
- else
- {
- assertThat( this.reportEntry.getStackTraceWriter() ).isNotNull();
-
- assertThat( reportEntry.getStackTraceWriter().getThrowable().getMessage() )
- .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getMessage() );
-
- assertThat( reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() )
- .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() );
-
- assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
- .isEqualTo( this.reportEntry.getStackTraceWriter().smartTrimmedStackTrace() );
- }
- }
- }
-
- private static class Stream extends PrintStream
- {
- private final ByteArrayOutputStream out;
-
- Stream( ByteArrayOutputStream out )
- {
- super( out, true );
- this.out = out;
- }
-
- byte[] toByteArray()
- {
- return out.toByteArray();
- }
-
- LineNumberReader newReader( Charset streamCharset )
- {
- return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
- }
-
- static Stream newStream()
- {
- return new Stream( new ByteArrayOutputStream() );
- }
- }
-
- private static byte[] toArray( ByteBuffer buffer )
- {
- return Arrays.copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
- }
-}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ConsoleOutputReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ConsoleOutputReporterTest.java
similarity index 95%
rename from maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ConsoleOutputReporterTest.java
rename to maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ConsoleOutputReporterTest.java
index 546e554..372c9a8 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ConsoleOutputReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ConsoleOutputReporterTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.extensions;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,10 +19,12 @@ package org.apache.maven.surefire.extensions;
* under the License.
*/
-import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter;
+import org.apache.maven.surefire.extensions.ConsoleOutputReportEventListener;
+import org.apache.maven.surefire.extensions.ConsoleOutputReporter;
import org.apache.maven.plugin.surefire.extensions.junit5.JUnit5ConsoleOutputReporter;
import org.apache.maven.plugin.surefire.report.ConsoleOutputFileReporter;
import org.apache.maven.plugin.surefire.report.DirectConsoleOutput;
+import org.fest.assertions.Assertions;
import org.junit.Test;
import java.io.File;
@@ -49,7 +51,7 @@ public class ConsoleOutputReporterTest
.isInstanceOf( SurefireConsoleOutputReporter.class );
assertThat( clone.toString() )
.isEqualTo( "SurefireConsoleOutputReporter{disable=true, encoding=ISO-8859-1}" );
- assertThat( ( (SurefireConsoleOutputReporter) clone ).isDisable() )
+ Assertions.assertThat( ( (SurefireConsoleOutputReporter) clone ).isDisable() )
.isTrue();
assertThat( ( (SurefireConsoleOutputReporter) clone ).getEncoding() )
.isEqualTo( "ISO-8859-1" );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
new file mode 100644
index 0000000..cb2e382
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
@@ -0,0 +1,1183 @@
+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.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessEventListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessEventNotifier;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessExitErrorListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessPropertyEventListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessReportEventListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStackTraceEventListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStandardOutErrEventListener;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkedProcessStringEventListener;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
+import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.util.internal.ObjectUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import javax.annotation.Nonnull;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.nio.channels.Channels.newChannel;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Arrays.copyOfRange;
+import static org.apache.commons.codec.binary.Base64.encodeBase64String;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.rules.ExpectedException.none;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test for {@link ForkedProcessEventNotifier}.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+@RunWith( Enclosed.class )
+public class ForkedProcessEventNotifierTest
+{
+ /**
+ *
+ */
+ @RunWith( PowerMockRunner.class )
+ @PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
+ public static class DecoderOperationsTest
+ {
+ @Rule
+ public final ExpectedException rule = none();
+
+ @Test
+ public void shouldBeFailSafe()
+ {
+ assertThat( EventConsumerThread.decode( null, UTF_8 ) ).isNull();
+ assertThat( EventConsumerThread.decode( "-", UTF_8 ) ).isNull();
+ assertThat( EventConsumerThread.decodeToInteger( null ) ).isNull();
+ assertThat( EventConsumerThread.decodeToInteger( "-" ) ).isNull();
+ }
+
+ @Test
+ public void shouldHaveSystemProperty() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ Map<String, String> props = ObjectUtils.systemProps();
+ encoder.sendSystemProperties( props );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ PropertyEventAssertionListener listener = new PropertyEventAssertionListener();
+ notifier.setSystemPropertiesListener( listener );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ for ( int i = 0; i < props.size(); i++ )
+ {
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+ }
+
+ assertThat( listener.counter.get() )
+ .isEqualTo( props.size() );
+ }
+
+ @Test
+ public void shouldRecognizeEmptyStream4ReportEntry()
+ {
+ ReportEntry reportEntry = EventConsumerThread.decodeReportEntry( null, null, null, "", "", null, null, "",
+ "", "", null );
+ assertThat( reportEntry ).isNull();
+
+ reportEntry = EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "-", "", "", "" );
+ assertThat( reportEntry ).isNotNull();
+ assertThat( reportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() ).isEmpty();
+ assertThat( reportEntry.getStackTraceWriter().writeTraceToString() ).isEmpty();
+ assertThat( reportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEmpty();
+ assertThat( reportEntry.getSourceName() ).isEmpty();
+ assertThat( reportEntry.getSourceText() ).isEmpty();
+ assertThat( reportEntry.getName() ).isEmpty();
+ assertThat( reportEntry.getNameText() ).isEmpty();
+ assertThat( reportEntry.getGroup() ).isEmpty();
+ assertThat( reportEntry.getNameWithGroup() ).isEmpty();
+ assertThat( reportEntry.getMessage() ).isEmpty();
+ assertThat( reportEntry.getElapsed() ).isNull();
+
+ rule.expect( NumberFormatException.class );
+ EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "", "", "", "" );
+ }
+
+ @Test
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ public void testCreatingReportEntry()
+ {
+ final String exceptionMessage = "msg";
+ final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
+
+ final String smartStackTrace = "MyTest:86 >> Error";
+ final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
+
+ final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
+ final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
+
+ final String trimmedStackTrace = "trace line 1\ntrace line 2";
+ final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
+
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( 102 );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( "skipped test" );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameText() ).thenReturn( "my display name" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
+ String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
+ String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
+ String encodedText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
+ String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
+ String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
+
+ ReportEntry decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName,
+ encodedSourceText, encodedName, encodedText, encodedGroup, encodedMessage, "-", null, null, null );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
+ encodedName, encodedText, encodedGroup, encodedMessage, "-", encodedExceptionMsg,
+ encodedSmartStackTrace, null );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isNull();
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
+ .isNull();
+
+ decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
+ encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
+ encodedSmartStackTrace, null );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
+ .isNull();
+
+ decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
+ encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
+ encodedSmartStackTrace, encodedStackTrace );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
+
+ decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
+ encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
+ encodedSmartStackTrace, encodedTrimmedStackTrace );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getSourceText() ).isEqualTo( reportEntry.getSourceText() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getNameText() ).isEqualTo( reportEntry.getNameText() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( trimmedStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() )
+ .isEqualTo( trimmedStackTrace );
+ }
+
+ @Test
+ public void shouldSendByeEvent() throws Exception
+ {
+ Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.bye();
+ String read = new String( out.toByteArray(), UTF_8 );
+
+ assertThat( read )
+ .isEqualTo( ":maven-surefire-event:bye:\n" );
+
+ LineNumberReader lines = out.newReader( UTF_8 );
+
+ final String cmd = lines.readLine();
+ assertThat( cmd )
+ .isNotNull();
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ EventAssertionListener listener = new EventAssertionListener();
+ notifier.setByeListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void shouldSendStopOnNextTestEvent() throws Exception
+ {
+ Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stopOnNextTest();
+ String read = new String( out.toByteArray(), UTF_8 );
+
+ assertThat( read )
+ .isEqualTo( ":maven-surefire-event:stop-on-next-test:\n" );
+
+ LineNumberReader lines = out.newReader( UTF_8 );
+
+ final String cmd = lines.readLine();
+ assertThat( cmd )
+ .isNotNull();
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ EventAssertionListener listener = new EventAssertionListener();
+ notifier.setStopOnNextTestListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void shouldCorrectlyDecodeStackTracesWithEmptyStringTraceMessages() throws Exception
+ {
+ String exceptionMessage = "";
+ String smartStackTrace = "JUnit5Test.failWithEmptyString:16";
+ String exceptionStackTrace = "org.opentest4j.AssertionFailedError: \n"
+ + "\tat JUnit5Test.failWithEmptyString(JUnit5Test.java:16)\n";
+
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( 7 );
+ when( reportEntry.getGroup() ).thenReturn( null );
+ when( reportEntry.getMessage() ).thenReturn( null );
+ when( reportEntry.getName() ).thenReturn( "failWithEmptyString" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "JUnit5Test" );
+ when( reportEntry.getSourceName() ).thenReturn( "JUnit5Test" );
+ when( reportEntry.getSourceText() ).thenReturn( null );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.testFailed( reportEntry, true );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ final ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ ReportEventAssertionListener listener = new ReportEventAssertionListener( reportEntry, true );
+ notifier.setTestFailedListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void shouldSendNextTestEvent() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.acquireNextTest();
+ String read = new String( out.toByteArray(), UTF_8 );
+
+ assertThat( read )
+ .isEqualTo( ":maven-surefire-event:next-test:\n" );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ EventAssertionListener listener = new EventAssertionListener();
+ notifier.setAcquireNextTestListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testConsole() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.consoleInfoLog( "msg" );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
+ notifier.setConsoleInfoListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testError() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.consoleErrorLog( "msg" );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StackTraceEventListener listener = new StackTraceEventListener( "msg", null, null );
+ notifier.setConsoleErrorListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testErrorWithException() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ Throwable throwable = new Throwable( "msg" );
+ encoder.consoleErrorLog( throwable );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ String stackTrace = ConsoleLoggerUtils.toString( throwable );
+ StackTraceEventListener listener = new StackTraceEventListener( "msg", null, stackTrace );
+ notifier.setConsoleErrorListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testErrorWithStackTraceWriter() throws Exception
+ {
+ final Stream out = Stream.newStream();
+
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "1", "2", "3" );
+ encoder.consoleErrorLog( stackTraceWriter, false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StackTraceEventListener listener = new StackTraceEventListener( "1", "2", "3" );
+ notifier.setConsoleErrorListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testDebug() throws Exception
+ {
+ final Stream out = Stream.newStream();
+
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.consoleDebugLog( "msg" );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
+ notifier.setConsoleDebugListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+
+ assertThat( listener.msg )
+ .isEqualTo( "msg" );
+ }
+
+ @Test
+ public void testWarning() throws Exception
+ {
+ final Stream out = Stream.newStream();
+
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.consoleWarningLog( "msg" );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StringEventAssertionListener listener = new StringEventAssertionListener( "msg" );
+ notifier.setConsoleWarningListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdOutStream() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdOut( "msg", false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false );
+ notifier.setStdOutListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdOutStreamPrint() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdOut( "", false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, "", false );
+ notifier.setStdOutListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdOutStreamPrintWithNull() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdOut( null, false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, null, false );
+ notifier.setStdOutListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdOutStreamPrintln() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdOut( "", true );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, "", true );
+ notifier.setStdOutListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdOutStreamPrintlnWithNull() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdOut( null, true );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, null, true );
+ notifier.setStdOutListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void testStdErrStream() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.stdErr( "msg", false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ StandardOutErrEventAssertionListener listener =
+ new StandardOutErrEventAssertionListener( NORMAL_RUN, "msg", false );
+ notifier.setStdErrListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void shouldCountSameNumberOfSystemProperties() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder.sendSystemProperties( ObjectUtils.systemProps() );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ PropertyEventAssertionListener listener = new PropertyEventAssertionListener();
+ notifier.setSystemPropertiesListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+
+ @Test
+ public void shouldHandleErrorAfterNullLine()
+ {
+ ForkedProcessEventNotifier decoder = new ForkedProcessEventNotifier();
+ decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
+ rule.expect( NullPointerException.class );
+ decoder.notifyEvent( null );
+ }
+
+ @Test
+ public void shouldHandleErrorAfterUnknownOperation() throws Exception
+ {
+ String cmd = ":maven-surefire-event:abnormal-run:-:\n";
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( cmd.getBytes() ) );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ countdown.awaitClosed();
+ }
+
+ verify( logger, times( 1 ) )
+ .error( eq( ":maven-surefire-event:abnormal-run:" ) );
+ }
+
+ @Test
+ public void shouldHandleExit() throws Exception
+ {
+ final Stream out = Stream.newStream();
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
+ encoder.sendExitEvent( stackTraceWriter, false );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+ ProcessExitErrorListener listener = new ProcessExitErrorListener();
+ notifier.setExitErrorEventListener( listener );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+
+ assertThat( listener.called.get() )
+ .isTrue();
+ }
+ }
+
+ /**
+ *
+ */
+ @RunWith( Theories.class )
+ public static class ReportEntryTest
+ {
+ @DataPoints( value = "operation" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static String[][] operations = { { "testSetStarting", "setTestSetStartingListener" },
+ { "testSetCompleted", "setTestSetCompletedListener" },
+ { "testStarting", "setTestStartingListener" },
+ { "testSucceeded", "setTestSucceededListener" },
+ { "testFailed", "setTestFailedListener" },
+ { "testSkipped", "setTestSkippedListener" },
+ { "testError", "setTestErrorListener" },
+ { "testAssumptionFailure", "setTestAssumptionFailureListener" }
+ };
+
+ @DataPoints( value = "reportedMessage" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static String[] reportedMessage = { null, "skipped test" };
+
+ @DataPoints( value = "elapsed" )
+ @SuppressWarnings( { "checkstyle:visibilitymodifier", "checkstyle:magicnumber" } )
+ public static Integer[] elapsed = { null, 102 };
+
+ @DataPoints( value = "trim" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static boolean[] trim = { false, true };
+
+ @DataPoints( value = "msg" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static boolean[] msg = { false, true };
+
+ @DataPoints( value = "smart" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static boolean[] smart = { false, true };
+
+ @DataPoints( value = "trace" )
+ @SuppressWarnings( "checkstyle:visibilitymodifier" )
+ public static boolean[] trace = { false, true };
+
+ @Theory
+ public void testReportEntryOperations( @FromDataPoints( "operation" ) String[] operation,
+ @FromDataPoints( "reportedMessage" ) String reportedMessage,
+ @FromDataPoints( "elapsed" ) Integer elapsed,
+ @FromDataPoints( "trim" ) boolean trim,
+ @FromDataPoints( "msg" ) boolean msg,
+ @FromDataPoints( "smart" ) boolean smart,
+ @FromDataPoints( "trace" ) boolean trace )
+ throws Exception
+ {
+ String exceptionMessage = msg ? "msg" : null;
+ String smartStackTrace = smart ? "MyTest:86 >> Error" : null;
+ String exceptionStackTrace =
+ trace ? ( trim ? "trace line 1\ntrace line 2" : "Exception: msg\ntrace line 1\ntrace line 2" )
+ : null;
+
+ StackTraceWriter stackTraceWriter = null;
+ if ( exceptionStackTrace != null )
+ {
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
+ }
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( elapsed );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( reportedMessage );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getName() ).thenReturn( "display name of test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ final Stream out = Stream.newStream();
+
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+
+ LegacyMasterProcessChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
+ .invoke( encoder, reportEntry, trim );
+
+ ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
+
+ ForkedProcessEventNotifier.class.getMethod( operation[1], ForkedProcessReportEventListener.class )
+ .invoke( notifier, new ReportEventAssertionListener( reportEntry, stackTraceWriter != null ) );
+
+ ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
+
+ EH eventHandler = new EH();
+ CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, logger ) )
+ {
+ t.start();
+ notifier.notifyEvent( eventHandler.pullEvent() );
+ }
+ }
+ }
+
+ private static class ProcessExitErrorListener implements ForkedProcessExitErrorListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+
+ @Override
+ public void handle( StackTraceWriter stackTrace )
+ {
+ called.set( true );
+ assertThat( stackTrace.getThrowable().getMessage() ).isEqualTo( "1" );
+ assertThat( stackTrace.smartTrimmedStackTrace() ).isEqualTo( "2" );
+ assertThat( stackTrace.writeTraceToString() ).isEqualTo( "3" );
+ }
+ }
+
+ private static class PropertyEventAssertionListener implements ForkedProcessPropertyEventListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+ private final Map<?, ?> sysProps = System.getProperties();
+ private final AtomicInteger counter = new AtomicInteger();
+
+ public void handle( RunMode runMode, String key, String value )
+ {
+ called.set( true );
+ counter.incrementAndGet();
+ assertThat( runMode ).isEqualTo( NORMAL_RUN );
+ assertTrue( sysProps.containsKey( key ) );
+ assertThat( sysProps.get( key ) ).isEqualTo( value );
+ }
+ }
+
+ private static class EventAssertionListener implements ForkedProcessEventListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+
+ public void handle()
+ {
+ called.set( true );
+ }
+ }
+
+ private static class StringEventAssertionListener implements ForkedProcessStringEventListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+ private final String msg;
+
+ StringEventAssertionListener( String msg )
+ {
+ this.msg = msg;
+ }
+
+ public void handle( String msg )
+ {
+ called.set( true );
+ assertThat( msg )
+ .isEqualTo( this.msg );
+ }
+ }
+
+ private static class StackTraceEventListener implements ForkedProcessStackTraceEventListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+ private final String msg;
+ private final String smartStackTrace;
+ private final String stackTrace;
+
+ StackTraceEventListener( String msg, String smartStackTrace, String stackTrace )
+ {
+ this.msg = msg;
+ this.smartStackTrace = smartStackTrace;
+ this.stackTrace = stackTrace;
+ }
+
+ @Override
+ public void handle( @Nonnull StackTraceWriter stackTrace )
+ {
+ called.set( true );
+
+ assertThat( stackTrace.getThrowable().getMessage() )
+ .isEqualTo( msg );
+
+ assertThat( stackTrace.smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+
+ assertThat( stackTrace.writeTraceToString() )
+ .isEqualTo( this.stackTrace );
+ }
+ }
+
+ private static class StandardOutErrEventAssertionListener implements ForkedProcessStandardOutErrEventListener
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+ private final RunMode runMode;
+ private final String output;
+ private final boolean newLine;
+
+ StandardOutErrEventAssertionListener( RunMode runMode, String output, boolean newLine )
+ {
+ this.runMode = runMode;
+ this.output = output;
+ this.newLine = newLine;
+ }
+
+ public void handle( RunMode runMode, String output, boolean newLine )
+ {
+ called.set( true );
+
+ assertThat( runMode )
+ .isEqualTo( this.runMode );
+
+ assertThat( output )
+ .isEqualTo( this.output );
+
+ assertThat( newLine )
+ .isEqualTo( this.newLine );
+ }
+ }
+
+ private static class ReportEventAssertionListener implements ForkedProcessReportEventListener<ReportEntry>
+ {
+ final AtomicBoolean called = new AtomicBoolean();
+ private final ReportEntry reportEntry;
+ private final boolean hasStackTrace;
+
+ ReportEventAssertionListener( ReportEntry reportEntry, boolean hasStackTrace )
+ {
+ this.reportEntry = reportEntry;
+ this.hasStackTrace = hasStackTrace;
+ }
+
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ called.set( true );
+ assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
+ assertThat( reportEntry.getSourceText() ).isEqualTo( this.reportEntry.getSourceText() );
+ assertThat( reportEntry.getName() ).isEqualTo( this.reportEntry.getName() );
+ assertThat( reportEntry.getNameText() ).isEqualTo( this.reportEntry.getNameText() );
+ assertThat( reportEntry.getGroup() ).isEqualTo( this.reportEntry.getGroup() );
+ assertThat( reportEntry.getMessage() ).isEqualTo( this.reportEntry.getMessage() );
+ assertThat( reportEntry.getElapsed() ).isEqualTo( this.reportEntry.getElapsed() );
+ if ( reportEntry.getStackTraceWriter() == null )
+ {
+ assertThat( hasStackTrace ).isFalse();
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNull();
+ }
+ else
+ {
+ assertThat( hasStackTrace ).isTrue();
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNotNull();
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().smartTrimmedStackTrace() );
+ }
+ }
+ }
+
+ private static class Stream extends PrintStream
+ {
+ private final ByteArrayOutputStream out;
+
+ Stream( ByteArrayOutputStream out )
+ {
+ super( out, true );
+ this.out = out;
+ }
+
+ byte[] toByteArray()
+ {
+ return out.toByteArray();
+ }
+
+ LineNumberReader newReader( Charset streamCharset )
+ {
+ return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
+ }
+
+ static Stream newStream()
+ {
+ return new Stream( new ByteArrayOutputStream() );
+ }
+ }
+
+ private static byte[] toArray( ByteBuffer buffer )
+ {
+ return copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
+ }
+
+ private static class EH implements EventHandler<Event>
+ {
+ private final BlockingQueue<Event> cache = new LinkedTransferQueue<>();
+
+ Event pullEvent() throws InterruptedException
+ {
+ return cache.poll( 1, TimeUnit.MINUTES );
+ }
+
+ @Override
+ public void handleEvent( @Nonnull Event event )
+ {
+ cache.add( event );
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StatelessReporterTest.java
similarity index 98%
rename from maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessReporterTest.java
rename to maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StatelessReporterTest.java
index bb06eff..4aa048c 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StatelessReporterTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.extensions;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,8 +19,7 @@ package org.apache.maven.surefire.extensions;
* under the License.
*/
-import org.apache.maven.plugin.surefire.extensions.DefaultStatelessReportMojoConfiguration;
-import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
+import org.apache.maven.surefire.extensions.StatelessReportEventListener;
import org.apache.maven.plugin.surefire.extensions.junit5.JUnit5Xml30StatelessReporter;
import org.apache.maven.plugin.surefire.report.StatelessXmlReporter;
import org.apache.maven.plugin.surefire.report.TestSetStats;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
new file mode 100644
index 0000000..7da6745
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
@@ -0,0 +1,162 @@
+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.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.Iterator;
+
+import static java.util.Arrays.asList;
+import static org.apache.maven.surefire.booter.Command.TEST_SET_FINISHED;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link StreamFeeder}.
+ */
+public class StreamFeederTest
+{
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private final WritableByteChannel channel = mock( WritableByteChannel.class );
+ private final CommandReader commandReader = mock( CommandReader.class );
+ private StreamFeeder streamFeeder;
+
+ @Before
+ public void setup() throws IOException
+ {
+ final Iterator<Command> it = asList( new Command( RUN_CLASS, "pkg.ATest" ), TEST_SET_FINISHED ).iterator();
+ when( commandReader.readNextCommand() )
+ .thenAnswer( new Answer<Command>()
+ {
+ @Override
+ public Command answer( InvocationOnMock invocation )
+ {
+ return it.hasNext() ? it.next() : null;
+ }
+ } );
+ }
+
+ @After
+ public void close() throws IOException
+ {
+ if ( streamFeeder != null )
+ {
+ streamFeeder.disable();
+ streamFeeder.close();
+ }
+ }
+
+ @Test
+ public void shouldEncodeCommandToStream() throws Exception
+ {
+ when( channel.write( any( ByteBuffer.class ) ) )
+ .thenAnswer( new Answer<Object>()
+ {
+ @Override
+ public Object answer( InvocationOnMock invocation ) throws IOException
+ {
+ ByteBuffer bb = invocation.getArgument( 0 );
+ bb.flip();
+ out.write( bb.array() );
+ return 0;
+ }
+ } );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ streamFeeder = new StreamFeeder( "t", channel, commandReader, logger );
+ streamFeeder.start();
+
+ streamFeeder.join();
+ String commands = out.toString();
+
+ assertThat( commands )
+ .isEqualTo( ":maven-surefire-command:run-testclass:pkg.ATest::maven-surefire-command:testset-finished:" );
+
+ verify( channel, times( 1 ) )
+ .close();
+
+ assertThat( streamFeeder.getException() )
+ .isNull();
+
+ verifyZeroInteractions( logger );
+ }
+
+ @Test
+ public void shouldFailThread() throws Exception
+ {
+ when( channel.write( any( ByteBuffer.class ) ) )
+ .thenAnswer( new Answer<Object>()
+ {
+ @Override
+ public Object answer( InvocationOnMock invocation ) throws IOException
+ {
+ throw new IOException();
+ }
+ } );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ streamFeeder = new StreamFeeder( "t", channel, commandReader, logger );
+ streamFeeder.start();
+
+ streamFeeder.join();
+
+ assertThat( out.size() )
+ .isZero();
+
+ verify( channel, times( 1 ) )
+ .close();
+
+ assertThat( streamFeeder.getException() )
+ .isNotNull()
+ .isInstanceOf( IOException.class );
+
+ verifyZeroInteractions( logger );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailWithoutData()
+ {
+ StreamFeeder.encode( RUN_CLASS );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailWithData()
+ {
+ StreamFeeder.encode( NOOP, "" );
+ }
+}
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..a232544 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;
@@ -41,7 +40,10 @@ import org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfigu
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
-import org.apache.maven.plugin.surefire.booterclient.output.ForkedChannelDecoderTest;
+import org.apache.maven.plugin.surefire.extensions.ConsoleOutputReporterTest;
+import org.apache.maven.plugin.surefire.extensions.ForkedProcessEventNotifierTest;
+import org.apache.maven.plugin.surefire.extensions.StatelessReporterTest;
+import org.apache.maven.plugin.surefire.extensions.StreamFeederTest;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactoryTest;
import org.apache.maven.plugin.surefire.report.StatelessXmlReporterTest;
import org.apache.maven.plugin.surefire.report.TestSetStatsTest;
@@ -51,8 +53,7 @@ import org.apache.maven.plugin.surefire.util.DependenciesScannerTest;
import org.apache.maven.plugin.surefire.util.DirectoryScannerTest;
import org.apache.maven.plugin.surefire.util.ScannerUtilTest;
import org.apache.maven.plugin.surefire.util.SpecificFileFilterTest;
-import org.apache.maven.surefire.extensions.ConsoleOutputReporterTest;
-import org.apache.maven.surefire.extensions.StatelessReporterTest;
+import org.apache.maven.surefire.extensions.ForkChannelTest;
import org.apache.maven.surefire.extensions.StatelessTestsetInfoReporterTest;
import org.apache.maven.surefire.report.FileReporterTest;
import org.apache.maven.surefire.report.RunStatisticsTest;
@@ -89,7 +90,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 ) );
@@ -99,13 +99,15 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( ScannerUtilTest.class ) );
suite.addTest( new JUnit4TestAdapter( MojoMocklessTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkClientTest.class ) );
- suite.addTest( new JUnit4TestAdapter( ForkedChannelDecoderTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( ForkedProcessEventNotifierTest.class ) );
suite.addTest( new JUnit4TestAdapter( ConsoleOutputReporterTest.class ) );
suite.addTest( new JUnit4TestAdapter( StatelessReporterTest.class ) );
suite.addTest( new JUnit4TestAdapter( TestSetStatsTest.class ) );
suite.addTest( new JUnit4TestAdapter( StatelessTestsetInfoReporterTest.class ) );
suite.addTest( new JUnit4TestAdapter( CommonReflectorTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkStarterTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( ForkChannelTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( StreamFeederTest.class ) );
return suite;
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
new file mode 100644
index 0000000..68f2324
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
@@ -0,0 +1,166 @@
+package org.apache.maven.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.plugin.surefire.booterclient.MockReporter;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
+import org.apache.maven.plugin.surefire.extensions.SurefireForkNodeFactory;
+import org.apache.maven.surefire.eventapi.ControlByeEvent;
+import org.apache.maven.surefire.eventapi.Event;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+import org.junit.Test;
+
+import javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URI;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ *
+ */
+public class ForkChannelTest
+{
+ private static final long TESTCASE_TIMEOUT = 30_000L;
+
+ private final AtomicBoolean hasError = new AtomicBoolean();
+
+ @Test( timeout = TESTCASE_TIMEOUT )
+ public void shouldRequestReplyMessagesViaTCP() throws Exception
+ {
+ ForkNodeFactory factory = new SurefireForkNodeFactory();
+ try ( ForkChannel channel = factory.createForkChannel( 1, new MockReporter() ) )
+ {
+ assertThat( channel.getForkChannelId() )
+ .isEqualTo( 1 );
+
+ assertThat( channel.useStdOut() )
+ .isFalse();
+
+ assertThat( channel.getForkNodeConnectionString() )
+ .startsWith( "tcp://127.0.0.1:" )
+ .isNotEqualTo( "tcp://127.0.0.1:" );
+
+ URI uri = new URI( channel.getForkNodeConnectionString() );
+
+ assertThat( uri.getPort() )
+ .isPositive();
+
+ Consumer consumer = new Consumer();
+
+ Client client = new Client( uri.getPort() );
+ client.start();
+
+ channel.connectToClient();
+ SECONDS.sleep( 3L );
+
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ TestLessInputStream commandReader = builder.build();
+
+ channel.bindCommandReader( commandReader, null ).start();
+
+ final AtomicBoolean isCloseableCalled = new AtomicBoolean();
+ Closeable closeable = new Closeable()
+ {
+ @Override
+ public void close()
+ {
+ isCloseableCalled.set( true );
+ }
+ };
+ CountdownCloseable cc = new CountdownCloseable( closeable, 1 );
+ channel.bindEventHandler( consumer, cc, null ).start();
+
+ SECONDS.sleep( 3L );
+
+ commandReader.noop();
+
+ SECONDS.sleep( 3L );
+
+ client.join( TESTCASE_TIMEOUT );
+
+ assertThat( hasError.get() )
+ .isFalse();
+
+ assertThat( isCloseableCalled.get() )
+ .isTrue();
+
+ assertThat( consumer.lines )
+ .hasSize( 1 );
+
+ assertThat( consumer.lines.element() )
+ .isInstanceOf( ControlByeEvent.class );
+ }
+ }
+
+ private static class Consumer implements EventHandler<Event>
+ {
+ final Queue<Event> lines = new ConcurrentLinkedQueue<>();
+
+ @Override
+ public void handleEvent( @Nonnull Event s )
+ {
+ lines.add( s );
+ }
+ }
+
+ private final class Client extends Thread
+ {
+ private final int port;
+
+ private Client( int port )
+ {
+ this.port = port;
+ }
+
+ @Override
+ public void run()
+ {
+ try ( Socket socket = new Socket( "127.0.0.1", port ) )
+ {
+ byte[] data = new byte[128];
+ int readLength = socket.getInputStream().read( data );
+ String token = new String( data, 0, readLength, US_ASCII );
+ assertThat( token ).isEqualTo( ":maven-surefire-command:noop:" );
+ socket.getOutputStream().write( ":maven-surefire-event:bye:".getBytes( US_ASCII ) );
+ }
+ catch ( IOException e )
+ {
+ hasError.set( true );
+ e.printStackTrace();
+ throw new IllegalStateException( e );
+ }
+ catch ( RuntimeException e )
+ {
+ hasError.set( true );
+ e.printStackTrace();
+ throw e;
+ }
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
index a626180..577bb91 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
@@ -26,8 +26,8 @@ import org.apache.maven.plugin.surefire.report.ConsoleReporter;
import org.apache.maven.plugin.surefire.report.FileReporter;
import org.apache.maven.plugin.surefire.report.TestSetStats;
import org.apache.maven.plugin.surefire.report.WrappedReportEntry;
-import org.apache.maven.surefire.shared.utils.logging.MessageUtils;
import org.apache.maven.surefire.report.TestSetReportEntry;
+import org.apache.maven.surefire.shared.utils.logging.MessageUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
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 f4f992e..ccf7c9e 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>
@@ -97,7 +98,7 @@
<plexus-java-version>1.0.5</plexus-java-version>
<!-- maven-shared-utils:3.2.0+ another behavior - broke Surefire performance - end of subprocess notification not arrived in ForkStarter -->
<mavenSharedUtilsVersion>3.1.0</mavenSharedUtilsVersion>
- <powermockVersion>2.0.4</powermockVersion>
+ <powermockVersion>2.0.5</powermockVersion>
<jacocoVersion>0.8.5</jacocoVersion>
<maven.surefire.scm.devConnection>scm:git:https://gitbox.apache.org/repos/asf/maven-surefire.git</maven.surefire.scm.devConnection>
<maven.site.path>surefire-archives/surefire-LATEST</maven.site.path>
@@ -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,10 +492,8 @@
</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>
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..6ac0ce2 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,8 @@ 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.MasterProcessChannelEncoder;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.DefaultDirectConsoleReporter;
@@ -46,15 +48,13 @@ 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 ForkedChannelEncoder forkedChannelEncoder;
+ private ReporterFactory reporterFactory;
+
+ private MasterProcessChannelEncoder masterProcessChannelEncoder;
private List<CommandLineOption> mainCliOptions = emptyList();
@@ -74,17 +74,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 +124,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;
@@ -141,11 +153,11 @@ public class BaseProviderFactory
@Override
public ConsoleStream getConsoleLogger()
{
- return insideFork ? new ForkingRunListener( forkedChannelEncoder, reporterConfiguration.isTrimStackTrace() )
- : new DefaultDirectConsoleReporter( reporterConfiguration.getOriginalSystemOut() );
+ return insideFork
+ ? new ForkingRunListener( masterProcessChannelEncoder, reporterConfiguration.isTrimStackTrace() )
+ : new DefaultDirectConsoleReporter( reporterConfiguration.getOriginalSystemOut() );
}
- @Override
public void setTestRequest( TestRequest testRequest )
{
this.testRequest = testRequest;
@@ -175,7 +187,6 @@ public class BaseProviderFactory
return testClassLoader;
}
- @Override
public void setProviderProperties( Map<String, String> providerProperties )
{
this.providerProperties = providerProperties;
@@ -193,13 +204,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 +220,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 +236,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 +253,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;
@@ -259,13 +264,13 @@ public class BaseProviderFactory
}
@Override
- public ForkedChannelEncoder getForkedChannelEncoder()
+ public MasterProcessChannelEncoder getForkedChannelEncoder()
{
- return forkedChannelEncoder;
+ return masterProcessChannelEncoder;
}
- public void setForkedChannelEncoder( ForkedChannelEncoder forkedChannelEncoder )
+ public void setForkedChannelEncoder( MasterProcessChannelEncoder masterProcessChannelEncoder )
{
- this.forkedChannelEncoder = forkedChannelEncoder;
+ this.masterProcessChannelEncoder = masterProcessChannelEncoder;
}
}
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/ForkedProcessEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEventType.java
similarity index 86%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEventType.java
index 74b9eb9..c1087ac 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEventType.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import javax.annotation.Nonnull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -30,7 +31,7 @@ import static java.util.Collections.unmodifiableMap;
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
-public enum ForkedProcessEvent
+public enum ForkedProcessEventType
{
BOOTERCODE_SYSPROPS( "sys-prop" ),
@@ -59,14 +60,14 @@ public enum ForkedProcessEvent
BOOTERCODE_JVM_EXIT_ERROR( "jvm-exit-error" );
- public static final String MAGIC_NUMBER = ":maven:surefire:std:out:";
+ public static final String MAGIC_NUMBER = "maven-surefire-event";
- public static final Map<String, ForkedProcessEvent> EVENTS = events();
+ private static final Map<String, ForkedProcessEventType> EVENTS = events();
- private static Map<String, ForkedProcessEvent> events()
+ private static Map<String, ForkedProcessEventType> events()
{
- Map<String, ForkedProcessEvent> events = new ConcurrentHashMap<>();
- for ( ForkedProcessEvent event : values() )
+ Map<String, ForkedProcessEventType> events = new ConcurrentHashMap<>();
+ for ( ForkedProcessEventType event : values() )
{
events.put( event.getOpcode(), event );
}
@@ -75,7 +76,7 @@ public enum ForkedProcessEvent
private final String opcode;
- ForkedProcessEvent( String opcode )
+ ForkedProcessEventType( String opcode )
{
this.opcode = opcode;
}
@@ -129,4 +130,9 @@ public enum ForkedProcessEvent
{
return this == BOOTERCODE_JVM_EXIT_ERROR;
}
+
+ public static ForkedProcessEventType byOpcode( @Nonnull String opcode )
+ {
+ return EVENTS.get( opcode );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
index 5bb16ee..1c6db50 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.suite.RunResult;
@@ -34,9 +35,9 @@ public class ForkingReporterFactory
{
private final boolean trimstackTrace;
- private final ForkedChannelEncoder eventChannel;
+ private final MasterProcessChannelEncoder eventChannel;
- public ForkingReporterFactory( boolean trimstackTrace, ForkedChannelEncoder eventChannel )
+ public ForkingReporterFactory( boolean trimstackTrace, MasterProcessChannelEncoder eventChannel )
{
this.trimstackTrace = trimstackTrace;
this.eventChannel = eventChannel;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index 528b607..6148149 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -20,6 +20,7 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReportEntry;
@@ -50,13 +51,13 @@ import static java.util.Objects.requireNonNull;
public class ForkingRunListener
implements RunListener, ConsoleLogger, ConsoleOutputReceiver, ConsoleStream
{
- private final ForkedChannelEncoder target;
+ private final MasterProcessChannelEncoder target;
private final boolean trim;
private volatile RunMode runMode = NORMAL_RUN;
- public ForkingRunListener( ForkedChannelEncoder target, boolean trim )
+ public ForkingRunListener( MasterProcessChannelEncoder target, boolean trim )
{
this.target = target;
this.trim = trim;
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..b6ae644 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,46 +19,34 @@ 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.
*
* @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( String.class ),
+ TEST_SET_FINISHED( Void.class ),
+ SKIP_SINCE_NEXT_TEST( Void.class ),
+ 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( Void.class ),
+ BYE_ACK( Void.class );
- private final int id;
+ public static final String MAGIC_NUMBER = "maven-surefire-command";
private final Class<?> dataType;
- MasterProcessCommand( int id, Class<?> dataType )
+ MasterProcessCommand( Class<?> dataType )
{
- this.id = id;
this.dataType = requireNonNull( dataType, "dataType cannot be null" );
}
- public int getId()
- {
- return id;
- }
-
public Class<?> getDataType()
{
return dataType;
@@ -68,123 +56,4 @@ public enum MasterProcessCommand
{
return dataType != Void.class;
}
-
- @SuppressWarnings( "checkstyle:magicnumber" )
- public byte[] encode( String data )
- {
- if ( !hasDataType() )
- {
- throw new IllegalArgumentException( "cannot use data without data type" );
- }
-
- if ( getDataType() != String.class )
- {
- 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;
- }
-
- @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 );
- }
- }
- }
-
... 7551 lines suppressed ...