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 2019/07/10 20:25:39 UTC
[maven-surefire] 01/03: 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 88be259007ca7329fae0ea2507ad936e0ae08f33
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Jul 6 17:51:13 2019 +0200
Extensions API and SPI. Polymorphism for remote and local process communication.
---
maven-surefire-common/pom.xml | 16 --
.../plugin/surefire/booterclient/ForkStarter.java | 18 +--
.../lazytestprovider/AbstractForkInputStream.java | 3 +-
.../DifferedChannelCommandSender.java | 20 ++-
.../lazytestprovider/TestLessInputStream.java | 2 +
.../lazytestprovider/TestProvidingInputStream.java | 5 +-
.../booterclient/output/ExecutableCommandline.java | 15 +-
.../output/NetworkingProcessExecutor.java | 30 ++--
.../booterclient/output/PipeProcessExecutor.java | 30 ++--
...BooterDeserializerStartupConfigurationTest.java | 2 +-
.../TestLessInputStreamBuilderTest.java | 10 +-
.../TestProvidingInputStreamTest.java | 10 +-
pom.xml | 1 +
.../maven/surefire/booter/BaseProviderFactory.java | 63 ++++----
.../org/apache/maven/surefire/booter/Command.java | 21 ++-
...Aware.java => MasterProcessChannelEncoder.java} | 30 +++-
.../surefire/booter/MasterProcessCommand.java | 157 ++++++------------
.../booter/ReporterConfigurationAware.java | 30 ----
.../surefire/booter/RunOrderParametersAware.java | 30 ----
.../surefire/booter/SurefireClassLoadersAware.java | 28 ----
.../maven/surefire/booter/SurefireReflector.java | 53 ++-----
.../surefire/booter/TestArtifactInfoAware.java | 30 ----
.../maven/surefire/booter/TestRequestAware.java | 30 ----
.../CommandChainReader.java} | 19 ++-
.../{booter => providerapi}/CommandListener.java | 4 +-
.../providerapi/MasterProcessChannelDecoder.java | 47 ++++++
.../surefire/providerapi/ProviderParameters.java | 5 +-
.../java/org/apache/maven/JUnit4SuiteTest.java | 6 -
.../surefire/booter/MasterProcessCommandTest.java | 176 ---------------------
surefire-booter/pom.xml | 21 +++
.../maven/surefire/booter/BooterDeserializer.java | 2 +-
.../maven/surefire/booter/CommandReader.java | 113 ++++++-------
.../apache/maven/surefire/booter/ForkedBooter.java | 54 +++++--
.../maven/surefire/booter/LazyTestsToRun.java | 10 +-
.../surefire/booter/ProviderConfiguration.java | 2 -
.../surefire/booter/StartupConfiguration.java | 5 +
.../spi/DefaultMasterProcessChannelDecoder.java | 160 +++++++++++++++++++
...DefaultMasterProcessChannelDecoderFactory.java} | 34 ++--
...MasterProcessCommandNoMagicNumberException.java | 17 +-
.../spi/MasterProcessUnknownCommandException.java | 18 ++-
...surefire.spi.MasterProcessChannelDecoderFactory | 1 +
.../maven/surefire/booter/CommandReaderTest.java | 40 ++---
.../java/org/apache/maven/surefire/booter/Foo.java | 28 ++--
.../maven/surefire/booter/JUnit4SuiteTest.java | 3 +
.../surefire/booter/MasterProcessCommandTest.java | 148 +++++++++++++++++
.../surefire/booter/NewClassLoaderRunner.java | 0
.../surefire/booter/SurefireReflectorTest.java | 0
.../maven/surefire/extensions/ForkedChannel.java | 36 ++++-
.../surefire/extensions/ForkedChannelServer.java | 30 +++-
surefire-extensions-spi/pom.xml | 41 +++++
.../spi/MasterProcessChannelDecoderFactory.java | 20 ++-
surefire-providers/pom.xml | 1 +
surefire-providers/surefire-junit-platform/pom.xml | 5 +
surefire-providers/surefire-junit3/pom.xml | 5 +
surefire-providers/surefire-junit4/pom.xml | 5 +
.../maven/surefire/junit4/JUnit4Provider.java | 9 +-
surefire-providers/surefire-junit47/pom.xml | 5 +
.../surefire/junitcore/JUnitCoreProvider.java | 9 +-
surefire-providers/surefire-testng/pom.xml | 5 +
.../maven/surefire/testng/TestNGProvider.java | 9 +-
60 files changed, 931 insertions(+), 796 deletions(-)
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index 896c8be..d7f6bef 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -131,22 +131,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/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index 5ee5538..1056c5a 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.DifferedChannelCommandSender;
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;
@@ -54,6 +54,7 @@ import javax.annotation.Nonnull;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
@@ -77,7 +78,6 @@ import static java.lang.System.currentTimeMillis;
import static java.lang.Thread.currentThread;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
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;
@@ -542,7 +542,7 @@ public class ForkStarter
private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
SurefireProperties effectiveSystemProperties, int forkNumber,
- AbstractForkInputStream testProvidingInputStream, boolean readTestsFromInStream )
+ DifferedChannelCommandSender commandSender, boolean readTestsFromInStream )
throws SurefireBooterForkException
{
final String tempDir;
@@ -581,10 +581,7 @@ public class ForkStarter
OutputStreamFlushableCommandline cli =
forkConfiguration.createCommandLine( startupConfiguration, forkNumber, dumpLogDir );
- if ( testProvidingInputStream != null )
- {
- testProvidingInputStream.setFlushReceiverProvider( cli );
- }
+ commandSender.setFlushReceiverProvider( cli );
cli.createArg().setValue( tempDir );
cli.createArg().setValue( DUMP_FILE_PREFIX + forkNumber );
@@ -594,9 +591,8 @@ public class ForkStarter
cli.createArg().setValue( systPropsFile.getName() );
}
- final ThreadedStreamConsumer threadedStreamConsumer = new ThreadedStreamConsumer( forkClient );
- final CloseableCloser closer = new CloseableCloser( forkNumber, threadedStreamConsumer,
- requireNonNull( testProvidingInputStream, "null param" ) );
+ ThreadedStreamConsumer threadedStreamConsumer = new ThreadedStreamConsumer( forkClient );
+ CloseableCloser closer = new CloseableCloser( forkNumber, threadedStreamConsumer, commandSender );
log.debug( "Forking command line: " + cli );
@@ -609,7 +605,7 @@ public class ForkStarter
new NativeStdErrStreamConsumer( forkClient.getDefaultReporterFactory() );
CommandLineCallable future =
- executeCommandLineAsCallable( cli, testProvidingInputStream, threadedStreamConsumer,
+ executeCommandLineAsCallable( cli, (InputStream) commandSender, threadedStreamConsumer,
stdErrConsumer, 0, closer, ISO_8859_1 );
currentForkClients.add( forkClient );
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/AbstractForkInputStream.java
index a884c15..6bc8cb8 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/AbstractForkInputStream.java
@@ -32,13 +32,14 @@ import static java.util.Objects.requireNonNull;
*/
public abstract class AbstractForkInputStream
extends InputStream
- implements NotifiableTestStream
+ implements DifferedChannelCommandSender
{
private volatile FlushReceiverProvider flushReceiverProvider;
/**
* @param flushReceiverProvider the provider for a flush receiver.
*/
+ @Override
public void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider )
{
this.flushReceiverProvider = requireNonNull( flushReceiverProvider );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DifferedChannelCommandSender.java
similarity index 58%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DifferedChannelCommandSender.java
index eddebed..894c219 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/DifferedChannelCommandSender.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,23 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.extensions.ForkedChannelServer;
-import java.util.List;
+import java.io.Closeable;
/**
- * CLI options in plugin (main) JVM process.
+ * Physical implementation of command sender.<br>
+ * Instance of {@link AbstractForkInputStream} (namely {@link TestLessInputStream} or {@link TestProvidingInputStream})
+ * or the implementation of {@link ForkedChannelServer} (supported by MOJO plugin configuration).
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public interface DifferedChannelCommandSender
+ extends NotifiableTestStream, Closeable
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ void setFlushReceiverProvider( FlushReceiverProvider flushReceiverProvider );
+
+ @Override
+ void close();
}
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 3014486..5cabe7b 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
@@ -21,8 +21,10 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.Shutdown;
+import org.apache.maven.surefire.extensions.ForkedChannelServer;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
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..a51bb37 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;
@@ -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
{
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ExecutableCommandline.java
similarity index 67%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ExecutableCommandline.java
index eddebed..67e56bb 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ExecutableCommandline.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,14 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.shared.utils.cli.CommandLineCallable;
+import org.apache.maven.shared.utils.cli.Commandline;
+import org.apache.maven.shared.utils.cli.StreamConsumer;
/**
- * CLI options in plugin (main) JVM process.
*
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
*/
-interface MainCliOptionsAware
+public interface ExecutableCommandline
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ CommandLineCallable executeCommandLineAsCallable( Commandline cli, StreamConsumer stdOut, StreamConsumer stdErr );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NetworkingProcessExecutor.java
similarity index 52%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NetworkingProcessExecutor.java
index eddebed..1da7063 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NetworkingProcessExecutor.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,29 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.shared.utils.cli.CommandLineCallable;
+import org.apache.maven.shared.utils.cli.Commandline;
+import org.apache.maven.shared.utils.cli.StreamConsumer;
+import org.apache.maven.surefire.extensions.ForkedChannelServer;
/**
- * CLI options in plugin (main) JVM process.
- *
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+final class NetworkingProcessExecutor
+ implements ExecutableCommandline
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final ForkedChannelServer forkedChannelServer;
+
+ NetworkingProcessExecutor( ForkedChannelServer forkedChannelServer )
+ {
+ this.forkedChannelServer = forkedChannelServer;
+ }
+
+ @Override
+ public CommandLineCallable executeCommandLineAsCallable( Commandline cli,
+ StreamConsumer stdOut, StreamConsumer stdErr )
+ {
+ return null;
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/PipeProcessExecutor.java
similarity index 51%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/PipeProcessExecutor.java
index eddebed..71b1a3c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/PipeProcessExecutor.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,29 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.AbstractForkInputStream;
+import org.apache.maven.shared.utils.cli.CommandLineCallable;
+import org.apache.maven.shared.utils.cli.Commandline;
+import org.apache.maven.shared.utils.cli.StreamConsumer;
/**
- * CLI options in plugin (main) JVM process.
- *
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+final class PipeProcessExecutor
+ implements ExecutableCommandline
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final AbstractForkInputStream forkInputStream;
+
+ PipeProcessExecutor( AbstractForkInputStream forkInputStream )
+ {
+ this.forkInputStream = forkInputStream;
+ }
+
+ @Override
+ public CommandLineCallable executeCommandLineAsCallable( Commandline cli,
+ StreamConsumer stdOut, StreamConsumer stdErr )
+ {
+ return null;
+ }
}
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 7a1a7e2..75ea65d 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
@@ -129,7 +129,7 @@ public class BooterDeserializerStartupConfigurationTest
false, null, 1 );
BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
assertNull( booterDeserializer.getPluginPid() );
- return booterDeserializer.getProviderConfiguration();
+ return booterDeserializer.getStartupConfiguration();
}
private ProviderConfiguration getProviderConfiguration()
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 5d9b5af..4d95588 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,11 +21,12 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import java.io.DataInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
@@ -35,7 +36,6 @@ 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.BYE_ACK;
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.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -138,13 +138,13 @@ public class TestLessInputStreamBuilderTest
{
TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
TestLessInputStream pluginIs = builder.build();
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( pluginIs, null );
builder.getImmediateCommands().acknowledgeByeEventReceived();
builder.getImmediateCommands().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 ) );
}
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 d120638..30f410c 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
@@ -21,9 +21,10 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.junit.Test;
-import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Queue;
@@ -33,7 +34,6 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@@ -141,13 +141,13 @@ public class TestProvidingInputStreamTest
throws IOException
{
TestProvidingInputStream pluginIs = new TestProvidingInputStream( new ConcurrentLinkedQueue<String>() );
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( pluginIs, null );
pluginIs.acknowledgeByeEventReceived();
pluginIs.noop();
- DataInputStream is = new DataInputStream( pluginIs );
- Command bye = decode( is );
+ Command bye = decoder.decode();
assertThat( bye, is( notNullValue() ) );
assertThat( bye.getCommandType(), is( BYE_ACK ) );
- Command noop = decode( is );
+ Command noop = decoder.decode();
assertThat( noop, is( notNullValue() ) );
assertThat( noop.getCommandType(), is( MasterProcessCommand.NOOP ) );
}
diff --git a/pom.xml b/pom.xml
index 78ebe81..fde43d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
<module>maven-failsafe-plugin</module>
<module>maven-surefire-report-plugin</module>
<module>surefire-its</module>
+ <module>surefire-extensions-spi</module>
</modules>
<scm>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
index ec05580..9d2dc73 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
@@ -20,6 +20,7 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.DefaultDirectConsoleReporter;
@@ -46,14 +47,12 @@ import static java.util.Collections.emptyList;
* @author Kristian Rosenvold
*/
public class BaseProviderFactory
- implements DirectoryScannerParametersAware, ReporterConfigurationAware, SurefireClassLoadersAware, TestRequestAware,
- ProviderPropertiesAware, ProviderParameters, TestArtifactInfoAware, RunOrderParametersAware, MainCliOptionsAware,
- FailFastAware, ShutdownAware
+ implements ProviderParameters
{
- private final ReporterFactory reporterFactory;
-
private final boolean insideFork;
+ private ReporterFactory reporterFactory;
+
private ForkedChannelEncoder forkedChannelEncoder;
private List<CommandLineOption> mainCliOptions = emptyList();
@@ -74,17 +73,27 @@ public class BaseProviderFactory
private int skipAfterFailureCount;
- private Shutdown shutdown;
-
private Integer systemExitTimeout;
- public BaseProviderFactory( ReporterFactory reporterFactory, boolean insideFork )
+ private CommandChainReader commandReader;
+
+ public BaseProviderFactory( boolean insideFork )
{
- this.reporterFactory = reporterFactory;
this.insideFork = insideFork;
}
@Override
+ public CommandChainReader getCommandReader()
+ {
+ return commandReader;
+ }
+
+ public void setCommandReader( CommandChainReader commandReader )
+ {
+ this.commandReader = commandReader;
+ }
+
+ @Override
@Deprecated
public DirectoryScanner getDirectoryScanner()
{
@@ -114,25 +123,27 @@ public class BaseProviderFactory
? null : new DefaultRunOrderCalculator( runOrderParameters, getThreadCount() );
}
+ public void setReporterFactory( ReporterFactory reporterFactory )
+ {
+ this.reporterFactory = reporterFactory;
+ }
+
@Override
public ReporterFactory getReporterFactory()
{
return reporterFactory;
}
- @Override
public void setDirectoryScannerParameters( DirectoryScannerParameters directoryScannerParameters )
{
this.directoryScannerParameters = directoryScannerParameters;
}
- @Override
public void setReporterConfiguration( ReporterConfiguration reporterConfiguration )
{
this.reporterConfiguration = reporterConfiguration;
}
- @Override
public void setClassLoaders( ClassLoader testClassLoader )
{
this.testClassLoader = testClassLoader;
@@ -145,7 +156,6 @@ public class BaseProviderFactory
: new DefaultDirectConsoleReporter( reporterConfiguration.getOriginalSystemOut() );
}
- @Override
public void setTestRequest( TestRequest testRequest )
{
this.testRequest = testRequest;
@@ -175,7 +185,6 @@ public class BaseProviderFactory
return testClassLoader;
}
- @Override
public void setProviderProperties( Map<String, String> providerProperties )
{
this.providerProperties = providerProperties;
@@ -193,13 +202,11 @@ public class BaseProviderFactory
return testArtifactInfo;
}
- @Override
public void setTestArtifactInfo( TestArtifactInfo testArtifactInfo )
{
this.testArtifactInfo = testArtifactInfo;
}
- @Override
public void setRunOrderParameters( RunOrderParameters runOrderParameters )
{
this.runOrderParameters = runOrderParameters;
@@ -211,7 +218,11 @@ public class BaseProviderFactory
return mainCliOptions;
}
- @Override
+ /**
+ * CLI options in plugin (main) JVM process.
+ *
+ * @param mainCliOptions options
+ */
public void setMainCliOptions( List<CommandLineOption> mainCliOptions )
{
this.mainCliOptions = mainCliOptions == null ? Collections.<CommandLineOption>emptyList() : mainCliOptions;
@@ -223,7 +234,11 @@ public class BaseProviderFactory
return skipAfterFailureCount;
}
- @Override
+ /**
+ * See the plugin configuration parameter "skipAfterFailureCount".
+ *
+ * @param skipAfterFailureCount the value in config parameter "skipAfterFailureCount"
+ */
public void setSkipAfterFailureCount( int skipAfterFailureCount )
{
this.skipAfterFailureCount = skipAfterFailureCount;
@@ -236,18 +251,6 @@ public class BaseProviderFactory
}
@Override
- public Shutdown getShutdown()
- {
- return shutdown;
- }
-
- @Override
- public void setShutdown( Shutdown shutdown )
- {
- this.shutdown = shutdown;
- }
-
- @Override
public Integer getSystemExitTimeout()
{
return systemExitTimeout;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/Command.java
index c5e5857..7a7e2ba 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.util.internal.StringUtils.isBlank;
import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
@@ -47,6 +49,11 @@ public final class Command
this.data = data;
}
+ public Command( MasterProcessCommand command )
+ {
+ this( command, null );
+ }
+
public static Command toShutdown( Shutdown shutdownType )
{
return new Command( SHUTDOWN, shutdownType.name() );
@@ -57,11 +64,6 @@ public final class Command
return new Command( RUN_CLASS, runClass );
}
- public Command( MasterProcessCommand command )
- {
- this( command, null );
- }
-
public MasterProcessCommand getCommandType()
{
return command;
@@ -78,18 +80,13 @@ public final class Command
*/
public Shutdown toShutdownData()
{
- if ( !isType( SHUTDOWN ) )
+ if ( command != SHUTDOWN )
{
throw new IllegalStateException( "expected MasterProcessCommand.SHUTDOWN" );
}
return isBlank( data ) ? DEFAULT : Shutdown.valueOf( data );
}
- public boolean isType( MasterProcessCommand command )
- {
- return command == this.command;
- }
-
@Override
public boolean equals( Object o )
{
@@ -105,7 +102,7 @@ public final class Command
Command arg = (Command) o;
- return command == arg.command && ( data == null ? arg.data == null : data.equals( arg.data ) );
+ return command == arg.command && Objects.equals( data, arg.data );
}
@Override
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
index eddebed..527782d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
@@ -19,17 +19,31 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
-
/**
- * CLI options in plugin (main) JVM process.
+ * magic number : opcode [: opcode specific data]*
+ * <br>
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public final class MasterProcessChannelEncoder
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+
+ private static final String MAGIC_NUMBER = ":maven:surefire:std:out:";
+
+ /**
+ * Encodes opcode and data.
+ *
+ * @param operation opcode
+ * @param data data
+ * @return encoded command
+ */
+ private static StringBuilder encode( String operation, String data )
+ {
+ StringBuilder s = new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( operation );
+
+ return data == null ? s : s.append( ':' ).append( data );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
index 7c4520f..61cf05f 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
@@ -19,44 +19,49 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.DataInputStream;
-import java.io.IOException;
-
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.Objects.requireNonNull;
-import static java.lang.String.format;
/**
* Commands which are sent from plugin to the forked jvm.
* Support and methods related to the commands.
+ * <br>
+ * <br>
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ * or data encoded with Base64
+ * <br>
+ * magic number : opcode [: Base64(opcode specific data)]*
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
public enum MasterProcessCommand
{
- RUN_CLASS( 0, String.class ),
- TEST_SET_FINISHED( 1, Void.class ),
- SKIP_SINCE_NEXT_TEST( 2, Void.class ),
- SHUTDOWN( 3, String.class ),
+ RUN_CLASS( "run-testclass", String.class ),
+ TEST_SET_FINISHED( "testset-finished", Void.class ),
+ SKIP_SINCE_NEXT_TEST( "skip-since-next-test", Void.class ),
+ SHUTDOWN( "shutdown", String.class ),
/** To tell a forked process that the master process is still alive. Repeated after 10 seconds. */
- NOOP( 4, Void.class ),
- BYE_ACK( 5, Void.class );
+ NOOP( "noop", Void.class ),
+ BYE_ACK( "bye-ack", Void.class );
+
+ private static final String MAGIC_NUMBER = ":maven-surefire-std-out:";
- private final int id;
+ private final String opcodeName;
private final Class<?> dataType;
- MasterProcessCommand( int id, Class<?> dataType )
+ MasterProcessCommand( String opcodeName, Class<?> dataType )
{
- this.id = id;
+ this.opcodeName = opcodeName;
this.dataType = requireNonNull( dataType, "dataType cannot be null" );
}
- public int getId()
+ public String getOpcode()
{
- return id;
+ return opcodeName;
}
public Class<?> getDataType()
@@ -69,7 +74,18 @@ public enum MasterProcessCommand
return dataType != Void.class;
}
- @SuppressWarnings( "checkstyle:magicnumber" )
+ public static MasterProcessCommand byOpcode( String opcode )
+ {
+ for ( MasterProcessCommand cmd : values() )
+ {
+ if ( cmd.opcodeName.equals( opcode ) )
+ {
+ return cmd;
+ }
+ }
+ return null;
+ }
+
public byte[] encode( String data )
{
if ( !hasDataType() )
@@ -82,109 +98,36 @@ public enum MasterProcessCommand
throw new IllegalArgumentException( "Data type can be only " + String.class );
}
- final byte[] dataBytes = fromDataType( data );
- final int len = dataBytes.length;
-
- final byte[] encoded = new byte[8 + len];
-
- final int command = getId();
- setCommandAndDataLength( command, len, encoded );
- System.arraycopy( dataBytes, 0, encoded, 8, len );
-
- return encoded;
+ return encode( opcodeName, data )
+ .toString()
+ .getBytes( US_ASCII );
}
- @SuppressWarnings( "checkstyle:magicnumber" )
public byte[] encode()
{
if ( getDataType() != Void.class )
{
throw new IllegalArgumentException( "Data type can be only " + getDataType() );
}
- byte[] encoded = new byte[8];
- int command = getId();
- setCommandAndDataLength( command, 0, encoded );
- return encoded;
- }
-
- public static Command decode( DataInputStream is )
- throws IOException
- {
- MasterProcessCommand command = resolve( is.readInt() );
- if ( command == null )
- {
- return null;
- }
- else
- {
- int dataLength = is.readInt();
- if ( dataLength > 0 )
- {
- byte[] buffer = new byte[ dataLength ];
- is.readFully( buffer );
-
- if ( command.getDataType() == Void.class )
- {
- throw new IOException( format( "Command %s unexpectedly read Void data with length %d.",
- command, dataLength ) );
- }
-
- String data = command.toDataTypeAsString( buffer );
- return new Command( command, data );
- }
- else
- {
- return new Command( command );
- }
- }
- }
- String toDataTypeAsString( byte... data )
- {
- switch ( this )
- {
- case RUN_CLASS:
- case SHUTDOWN:
- return new String( data, US_ASCII );
- default:
- return null;
- }
+ return encode( opcodeName, null )
+ .toString()
+ .getBytes( US_ASCII );
}
- byte[] fromDataType( String data )
+ /**
+ * Encodes opcode and data.
+ *
+ * @param operation opcode
+ * @param data data
+ * @return encoded command
+ */
+ private static StringBuilder encode( String operation, String data )
{
- switch ( this )
- {
- case RUN_CLASS:
- case SHUTDOWN:
- return data.getBytes( US_ASCII );
- default:
- return new byte[0];
- }
- }
-
- static MasterProcessCommand resolve( int id )
- {
- for ( MasterProcessCommand command : values() )
- {
- if ( id == command.id )
- {
- return command;
- }
- }
- return null;
- }
+ StringBuilder s = new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( operation );
- @SuppressWarnings( "checkstyle:magicnumber" )
- static void setCommandAndDataLength( int command, int dataLength, byte... encoded )
- {
- encoded[0] = (byte) ( command >>> 24 );
- encoded[1] = (byte) ( command >>> 16 );
- encoded[2] = (byte) ( command >>> 8 );
- encoded[3] = (byte) command;
- encoded[4] = (byte) ( dataLength >>> 24 );
- encoded[5] = (byte) ( dataLength >>> 16 );
- encoded[6] = (byte) ( dataLength >>> 8 );
- encoded[7] = (byte) dataLength;
+ return data == null ? s : s.append( ':' ).append( data );
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java
deleted file mode 100644
index 8c65be3..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ReporterConfigurationAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.report.ReporterConfiguration;
-
-/**
- * @author Kristian Rosenvold
- */
-interface ReporterConfigurationAware
-{
- void setReporterConfiguration( ReporterConfiguration reporterConfiguration );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java
deleted file mode 100644
index 3bee07d..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/RunOrderParametersAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.RunOrderParameters;
-
-/**
- * @author Kristian Rosenvold
- */
-interface RunOrderParametersAware
-{
- void setRunOrderParameters( RunOrderParameters runOrderParameters );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java
deleted file mode 100644
index c2f5d99..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireClassLoadersAware.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * @author Kristian Rosenvold
- */
-interface SurefireClassLoadersAware
-{
- void setClassLoaders( ClassLoader testClassLoader );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
index 5cc1415..0be675d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/SurefireReflector.java
@@ -59,7 +59,7 @@ import static org.apache.maven.surefire.util.ReflectionUtils.newInstance;
*
* @author Kristian Rosenvold
*/
-public class SurefireReflector
+public final class SurefireReflector
{
private final ClassLoader surefireClassLoader;
@@ -69,21 +69,11 @@ public class SurefireReflector
private final Class<?> testArtifactInfo;
- private final Class<?> testArtifactInfoAware;
-
private final Class<?> directoryScannerParameters;
private final Class<?> runOrderParameters;
- private final Class<?> directoryScannerParametersAware;
-
- private final Class<?> testSuiteDefinitionAware;
-
- private final Class<?> testClassLoaderAware;
-
- private final Class<?> reporterConfigurationAware;
-
- private final Class<?> providerPropertiesAware;
+ private final Class<?> baseProviderFactory;
private final Class<?> runResult;
@@ -93,12 +83,8 @@ public class SurefireReflector
private final Class<?> testListResolver;
- private final Class<?> mainCliOptions;
-
private final Class<Enum> commandLineOptionsClass;
- private final Class<?> shutdownAwareClass;
-
private final Class<Enum> shutdownClass;
@SuppressWarnings( "unchecked" )
@@ -110,22 +96,14 @@ public class SurefireReflector
reporterConfiguration = surefireClassLoader.loadClass( ReporterConfiguration.class.getName() );
testRequest = surefireClassLoader.loadClass( TestRequest.class.getName() );
testArtifactInfo = surefireClassLoader.loadClass( TestArtifactInfo.class.getName() );
- testArtifactInfoAware = surefireClassLoader.loadClass( TestArtifactInfoAware.class.getName() );
directoryScannerParameters = surefireClassLoader.loadClass( DirectoryScannerParameters.class.getName() );
runOrderParameters = surefireClassLoader.loadClass( RunOrderParameters.class.getName() );
- directoryScannerParametersAware =
- surefireClassLoader.loadClass( DirectoryScannerParametersAware.class.getName() );
- testSuiteDefinitionAware = surefireClassLoader.loadClass( TestRequestAware.class.getName() );
- testClassLoaderAware = surefireClassLoader.loadClass( SurefireClassLoadersAware.class.getName() );
- reporterConfigurationAware = surefireClassLoader.loadClass( ReporterConfigurationAware.class.getName() );
- providerPropertiesAware = surefireClassLoader.loadClass( ProviderPropertiesAware.class.getName() );
+ baseProviderFactory = surefireClassLoader.loadClass( BaseProviderFactory.class.getName() );
reporterFactory = surefireClassLoader.loadClass( ReporterFactory.class.getName() );
runResult = surefireClassLoader.loadClass( RunResult.class.getName() );
booterParameters = surefireClassLoader.loadClass( ProviderParameters.class.getName() );
testListResolver = surefireClassLoader.loadClass( TestListResolver.class.getName() );
- mainCliOptions = surefireClassLoader.loadClass( MainCliOptionsAware.class.getName() );
commandLineOptionsClass = (Class<Enum>) surefireClassLoader.loadClass( CommandLineOption.class.getName() );
- shutdownAwareClass = surefireClassLoader.loadClass( ShutdownAware.class.getName() );
shutdownClass = (Class<Enum>) surefireClassLoader.loadClass( Shutdown.class.getName() );
}
catch ( ClassNotFoundException e )
@@ -241,7 +219,7 @@ public class SurefireReflector
public void setIfDirScannerAware( Object o, DirectoryScannerParameters dirScannerParams )
{
- if ( directoryScannerParametersAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setDirectoryScannerParameters( o, dirScannerParams );
}
@@ -249,7 +227,7 @@ public class SurefireReflector
public void setMainCliOptions( Object o, List<CommandLineOption> options )
{
- if ( mainCliOptions.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
List<Enum> newOptions = checkedList( new ArrayList<Enum>( options.size() ), commandLineOptionsClass );
Collection<Integer> ordinals = toOrdinals( options );
@@ -271,15 +249,12 @@ public class SurefireReflector
public void setShutdown( Object o, Shutdown shutdown )
{
- if ( shutdownAwareClass.isAssignableFrom( o.getClass() ) )
+ for ( Enum e : shutdownClass.getEnumConstants() )
{
- for ( Enum e : shutdownClass.getEnumConstants() )
+ if ( shutdown.ordinal() == e.ordinal() )
{
- if ( shutdown.ordinal() == e.ordinal() )
- {
- invokeSetter( o, "setShutdown", shutdownClass, e );
- break;
- }
+ invokeSetter( o, "setShutdown", shutdownClass, e );
+ break;
}
}
}
@@ -303,7 +278,7 @@ public class SurefireReflector
public void setTestSuiteDefinitionAware( Object o, TestRequest testSuiteDefinition2 )
{
- if ( testSuiteDefinitionAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestSuiteDefinition( o, testSuiteDefinition2 );
}
@@ -317,7 +292,7 @@ public class SurefireReflector
public void setProviderPropertiesAware( Object o, Map<String, String> properties )
{
- if ( providerPropertiesAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setProviderProperties( o, properties );
}
@@ -330,7 +305,7 @@ public class SurefireReflector
public void setReporterConfigurationAware( Object o, ReporterConfiguration reporterConfiguration1 )
{
- if ( reporterConfigurationAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setReporterConfiguration( o, reporterConfiguration1 );
}
@@ -344,7 +319,7 @@ public class SurefireReflector
public void setTestClassLoaderAware( Object o, ClassLoader testClassLoader )
{
- if ( testClassLoaderAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestClassLoader( o, testClassLoader );
}
@@ -358,7 +333,7 @@ public class SurefireReflector
public void setTestArtifactInfoAware( Object o, TestArtifactInfo testArtifactInfo1 )
{
- if ( testArtifactInfoAware.isAssignableFrom( o.getClass() ) )
+ if ( baseProviderFactory.isAssignableFrom( o.getClass() ) )
{
setTestArtifactInfo( o, testArtifactInfo1 );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java
deleted file mode 100644
index 9898061..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestArtifactInfoAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.TestArtifactInfo;
-
-/**
- * @author Kristian Rosenvold
- */
-interface TestArtifactInfoAware
-{
- void setTestArtifactInfo( TestArtifactInfo testArtifactInfo );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java
deleted file mode 100644
index 3e98b92..0000000
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/TestRequestAware.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.surefire.testset.TestRequest;
-
-/**
- * @author Kristian Rosenvold
- */
-interface TestRequestAware
-{
- void setTestRequest( TestRequest testSuiteDefinition );
-}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
similarity index 62%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
index caedb98..2c94e9d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ProviderPropertiesAware.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandChainReader.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.providerapi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.util.Map;
+import org.apache.maven.surefire.testset.TestSetFailedException;
/**
- * @author Kristian Rosenvold
+ * Hiding CommandReader instance in provider.
*/
-interface ProviderPropertiesAware
+public interface CommandChainReader
{
- void setProviderProperties( Map<String, String> providerProperties );
+ boolean awaitStarted()
+ throws TestSetFailedException;
+
+ void addTestsFinishedListener( CommandListener listener );
+
+ void addSkipNextTestsListener( CommandListener listener );
+
+ void addShutdownListener( CommandListener listener );
+
+ void removeListener( CommandListener listener );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
similarity index 90%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
index 523ca76..b0d8870 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/CommandListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.providerapi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.booter.Command;
+
/**
* Command listener interface.
*/
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
new file mode 100644
index 0000000..6c64b25
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
@@ -0,0 +1,47 @@
+package org.apache.maven.surefire.providerapi;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.booter.Command;
+
+import java.io.IOException;
+
+/**
+ * An abstraction for physical decoder of commands. The commands are sent from master Maven process and
+ * received by the child forked Surefire process. The session must be open after the MasterProcessChannelDecoderFactory
+ * has created the decoder instance. The session can be closed on the decoder instance.
+ */
+public interface MasterProcessChannelDecoder
+ extends AutoCloseable
+{
+ /**
+ * Reads the bytes from a channel, waiting until the command is read completely or
+ * the channel throws {@link java.io.EOFException}.
+ * <br>
+ * This method is called in a single Thread. The constructor can be called within another thread.
+ *
+ * @return decoded command
+ * @throws IOException exception in channel
+ */
+ Command decode() throws IOException;
+
+ @Override
+ void close() throws IOException;
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
index 0fea537..e4caae7 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.providerapi;
*/
import org.apache.maven.surefire.booter.ForkedChannelEncoder;
-import org.apache.maven.surefire.booter.Shutdown;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReporterConfiguration;
@@ -147,9 +146,9 @@ public interface ProviderParameters
*/
boolean isInsideFork();
- Shutdown getShutdown();
-
Integer getSystemExitTimeout();
ForkedChannelEncoder getForkedChannelEncoder();
+
+ CommandChainReader getCommandReader();
}
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index 38f0c48..ea27d8a 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -23,11 +23,8 @@ import junit.framework.JUnit4TestAdapter;
import junit.framework.Test;
import org.apache.maven.plugin.surefire.runorder.ThreadedExecutionSchedulerTest;
import org.apache.maven.surefire.SpecificTestClassFilterTest;
-import org.apache.maven.surefire.booter.CommandReaderTest;
import org.apache.maven.surefire.booter.ForkedChannelEncoderTest;
import org.apache.maven.surefire.booter.ForkingRunListenerTest;
-import org.apache.maven.surefire.booter.MasterProcessCommandTest;
-import org.apache.maven.surefire.booter.SurefireReflectorTest;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriterTest;
import org.apache.maven.surefire.suite.RunResultTest;
import org.apache.maven.surefire.testset.FundamentalFilterTest;
@@ -51,11 +48,8 @@ import org.junit.runners.Suite;
* @since 2.19
*/
@Suite.SuiteClasses( {
- CommandReaderTest.class,
ThreadedExecutionSchedulerTest.class,
ForkingRunListenerTest.class,
- MasterProcessCommandTest.class,
- SurefireReflectorTest.class,
LegacyPojoStackTraceWriterTest.class,
RunResultTest.class,
ResolvedTestTest.class,
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
deleted file mode 100644
index 19740fd..0000000
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package org.apache.maven.surefire.booter;
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import junit.framework.TestCase;
-import org.junit.Rule;
-import org.junit.rules.ExpectedException;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-
-import static org.apache.maven.surefire.booter.MasterProcessCommand.*;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
-
-/**
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
- */
-public class MasterProcessCommandTest
- extends TestCase
-{
- @Rule
- public final ExpectedException exception = ExpectedException.none();
-
- public void testEncodedStreamSequence()
- {
- byte[] streamSequence = new byte[10];
- streamSequence[8] = (byte) 'T';
- streamSequence[9] = (byte) 'e';
- setCommandAndDataLength( 256, 2, streamSequence );
- assertEquals( streamSequence[0], (byte) 0 );
- assertEquals( streamSequence[1], (byte) 0 );
- assertEquals( streamSequence[2], (byte) 1 );
- assertEquals( streamSequence[3], (byte) 0 );
- assertEquals( streamSequence[4], (byte) 0 );
- assertEquals( streamSequence[5], (byte) 0 );
- assertEquals( streamSequence[6], (byte) 0 );
- assertEquals( streamSequence[7], (byte) 2 );
- // remain unchanged
- assertEquals( streamSequence[8], (byte) 'T' );
- assertEquals( streamSequence[9], (byte) 'e' );
- }
-
- public void testResolved()
- {
- for ( MasterProcessCommand command : MasterProcessCommand.values() )
- {
- assertThat( command, is( resolve( command.getId() ) ) );
- }
- }
-
- public void testDataToByteArrayAndBack()
- {
- String dummyData = "pkg.Test";
- for ( MasterProcessCommand command : MasterProcessCommand.values() )
- {
- switch ( command )
- {
- case RUN_CLASS:
- assertEquals( String.class, command.getDataType() );
- byte[] encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 8 ) );
- assertThat( encoded[0], is( (byte) 'p' ) );
- assertThat( encoded[1], is( (byte) 'k' ) );
- assertThat( encoded[2], is( (byte) 'g' ) );
- assertThat( encoded[3], is( (byte) '.' ) );
- assertThat( encoded[4], is( (byte) 'T' ) );
- assertThat( encoded[5], is( (byte) 'e' ) );
- assertThat( encoded[6], is( (byte) 's' ) );
- assertThat( encoded[7], is( (byte) 't' ) );
- String decoded = command.toDataTypeAsString( encoded );
- assertThat( decoded, is( dummyData ) );
- break;
- case TEST_SET_FINISHED:
- assertEquals( Void.class, command.getDataType() );
- encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 0 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertNull( decoded );
- break;
- case SKIP_SINCE_NEXT_TEST:
- assertEquals( Void.class, command.getDataType() );
- encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 0 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertNull( decoded );
- break;
- case SHUTDOWN:
- assertEquals( String.class, command.getDataType() );
- encoded = command.fromDataType( Shutdown.EXIT.name() );
- assertThat( encoded.length, is( 4 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertThat( decoded, is( Shutdown.EXIT.name() ) );
- break;
- case NOOP:
- assertEquals( Void.class, command.getDataType() );
- encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 0 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertNull( decoded );
- break;
- case BYE_ACK:
- assertEquals( Void.class, command.getDataType() );
- encoded = command.fromDataType( dummyData );
- assertThat( encoded.length, is( 0 ) );
- decoded = command.toDataTypeAsString( encoded );
- assertNull( decoded );
- break;
- default:
- fail();
- }
- assertThat( command, is( resolve( command.getId() ) ) );
- }
- }
-
- public void testEncodedDecodedIsSameForRunClass()
- throws IOException
- {
- byte[] encoded = RUN_CLASS.encode( "pkg.Test" );
- assertThat( encoded.length, is( 16 ) );
- assertThat( encoded[0], is( (byte) 0 ) );
- assertThat( encoded[1], is( (byte) 0 ) );
- assertThat( encoded[2], is( (byte) 0 ) );
- assertThat( encoded[3], is( (byte) 0 ) );
- assertThat( encoded[4], is( (byte) 0 ) );
- assertThat( encoded[5], is( (byte) 0 ) );
- assertThat( encoded[6], is( (byte) 0 ) );
- assertThat( encoded[7], is( (byte) 8 ) );
- assertThat( encoded[8], is( (byte) 'p' ) );
- assertThat( encoded[9], is( (byte) 'k' ) );
- assertThat( encoded[10], is( (byte) 'g' ) );
- assertThat( encoded[11], is( (byte) '.' ) );
- assertThat( encoded[12], is( (byte) 'T' ) );
- assertThat( encoded[13], is( (byte) 'e' ) );
- assertThat( encoded[14], is( (byte) 's' ) );
- assertThat( encoded[15], is( (byte) 't' ) );
- Command command = decode( new DataInputStream( new ByteArrayInputStream( encoded ) ) );
- assertNotNull( command );
- assertThat( command.getCommandType(), is( RUN_CLASS ) );
- assertThat( command.getData(), is( "pkg.Test" ) );
- }
-
- public void testShouldDecodeTwoCommands() throws IOException
- {
- byte[] cmd1 = BYE_ACK.encode();
- byte[] cmd2 = NOOP.encode();
- byte[] stream = new byte[cmd1.length + cmd2.length];
- System.arraycopy( cmd1, 0, stream, 0, cmd1.length );
- System.arraycopy( cmd2, 0, stream, cmd1.length, cmd2.length );
- DataInputStream is = new DataInputStream( new ByteArrayInputStream( stream ) );
- Command bye = decode( is );
- assertNotNull( bye );
- assertThat( bye.getCommandType(), is( BYE_ACK ) );
- Command noop = decode( is );
- assertNotNull( noop );
- assertThat( noop.getCommandType(), is( NOOP ) );
- }
-}
diff --git a/surefire-booter/pom.xml b/surefire-booter/pom.xml
index 460293d..efa3124 100644
--- a/surefire-booter/pom.xml
+++ b/surefire-booter/pom.xml
@@ -44,6 +44,11 @@
</exclusions>
</dependency>
<dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-extensions-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-utils</artifactId>
<scope>test</scope>
@@ -97,6 +102,22 @@
<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/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
index 75aad1f..6bc3cae 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -122,7 +122,7 @@ public class BooterDeserializer
systemExitTimeout );
}
- public StartupConfiguration getProviderConfiguration()
+ public StartupConfiguration getStartupConfiguration()
{
boolean useSystemClassLoader = properties.getBooleanProperty( USESYSTEMCLASSLOADER );
boolean useManifestOnlyJar = properties.getBooleanProperty( USEMANIFESTONLYJAR );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
similarity index 83%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
rename to surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index b4e303e..a883ad1 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -20,10 +20,13 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.booter.spi.MasterProcessCommandNoMagicNumberException;
+import org.apache.maven.surefire.booter.spi.MasterProcessUnknownCommandException;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
-import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Iterator;
@@ -47,7 +50,6 @@ import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
import static org.apache.maven.surefire.booter.MasterProcessCommand.TEST_SET_FINISHED;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThread;
import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
@@ -58,12 +60,10 @@ import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
-public final class CommandReader
+public final class CommandReader implements CommandChainReader
{
private static final String LAST_TEST_SYMBOL = "";
- private static final CommandReader READER = new CommandReader();
-
private final Queue<BiProperty<MasterProcessCommand, CommandListener>> listeners = new ConcurrentLinkedQueue<>();
private final Thread commandThread = newDaemonThread( new CommandRunnable(), "surefire-forkedjvm-command-thread" );
@@ -76,38 +76,24 @@ public final class CommandReader
private final CopyOnWriteArrayList<String> testClasses = new CopyOnWriteArrayList<>();
- private volatile Shutdown shutdown;
-
- private int iteratedCount;
+ private final MasterProcessChannelDecoder decoder;
- private volatile ConsoleLogger logger = new NullConsoleLogger();
-
- private CommandReader()
- {
- }
+ private final Shutdown shutdown;
- public static CommandReader getReader()
- {
- final CommandReader reader = READER;
- if ( reader.state.compareAndSet( NEW, RUNNABLE ) )
- {
- reader.commandThread.start();
- }
- return reader;
- }
+ private final ConsoleLogger logger;
- public CommandReader setShutdown( Shutdown shutdown )
- {
- this.shutdown = shutdown;
- return this;
- }
+ private int iteratedCount;
- public CommandReader setLogger( ConsoleLogger logger )
+ public CommandReader( MasterProcessChannelDecoder decoder, Shutdown shutdown, ConsoleLogger logger )
{
+ this.decoder = requireNonNull( decoder, "null decoder" );
+ this.shutdown = requireNonNull( shutdown, "null Shutdown config" );
this.logger = requireNonNull( logger, "null logger" );
- return this;
+ state.set( RUNNABLE );
+ commandThread.start();
}
+ @Override
public boolean awaitStarted()
throws TestSetFailedException
{
@@ -143,11 +129,13 @@ public final class CommandReader
addListener( RUN_CLASS, listener );
}
+ @Override
public void addTestsFinishedListener( CommandListener listener )
{
addListener( TEST_SET_FINISHED, listener );
}
+ @Override
public void addSkipNextTestsListener( CommandListener listener )
{
addListener( SKIP_SINCE_NEXT_TEST, listener );
@@ -173,6 +161,7 @@ public final class CommandReader
listeners.add( new BiProperty<>( cmd, listener ) );
}
+ @Override
public void removeListener( CommandListener listener )
{
for ( Iterator<BiProperty<MasterProcessCommand, CommandListener>> it = listeners.iterator(); it.hasNext(); )
@@ -373,48 +362,37 @@ public final class CommandReader
public void run()
{
CommandReader.this.startMonitor.countDown();
- DataInputStream stdIn = new DataInputStream( System.in );
boolean isTestSetFinished = false;
try
{
while ( CommandReader.this.state.get() == RUNNABLE )
{
- Command command = decode( stdIn );
- if ( command == null )
- {
- String errorMessage = "[SUREFIRE] std/in stream corrupted: first sequence not recognized";
- DumpErrorSingleton.getSingleton().dumpStreamText( errorMessage );
- logger.error( errorMessage );
- break;
- }
- else
+ Command command = CommandReader.this.decoder.decode();
+ switch ( command.getCommandType() )
{
- switch ( command.getCommandType() )
- {
- case RUN_CLASS:
- String test = command.getData();
- boolean inserted = CommandReader.this.insertToQueue( test );
- if ( inserted )
- {
- CommandReader.this.wakeupIterator();
- insertToListeners( command );
- }
- break;
- case TEST_SET_FINISHED:
- CommandReader.this.makeQueueFull();
- isTestSetFinished = true;
+ case RUN_CLASS:
+ String test = command.getData();
+ boolean inserted = CommandReader.this.insertToQueue( test );
+ if ( inserted )
+ {
CommandReader.this.wakeupIterator();
insertToListeners( command );
- break;
- case SHUTDOWN:
- CommandReader.this.makeQueueFull();
- CommandReader.this.wakeupIterator();
- insertToListeners( command );
- break;
- default:
- insertToListeners( command );
- break;
- }
+ }
+ break;
+ case TEST_SET_FINISHED:
+ CommandReader.this.makeQueueFull();
+ isTestSetFinished = true;
+ CommandReader.this.wakeupIterator();
+ insertToListeners( command );
+ break;
+ case SHUTDOWN:
+ CommandReader.this.makeQueueFull();
+ CommandReader.this.wakeupIterator();
+ insertToListeners( command );
+ break;
+ default:
+ insertToListeners( command );
+ break;
}
}
}
@@ -432,6 +410,11 @@ public final class CommandReader
// does not go to finally for non-default config: Shutdown.EXIT or Shutdown.KILL
}
}
+ catch ( MasterProcessCommandNoMagicNumberException | MasterProcessUnknownCommandException e )
+ {
+ DumpErrorSingleton.getSingleton().dumpStreamException( e );
+ CommandReader.this.logger.error( e );
+ }
catch ( IOException e )
{
CommandReader.this.state.set( TERMINATED );
@@ -440,7 +423,7 @@ public final class CommandReader
{
String msg = "[SUREFIRE] std/in stream corrupted";
DumpErrorSingleton.getSingleton().dumpStreamException( e, msg );
- logger.error( msg, e );
+ CommandReader.this.logger.error( msg, e );
}
}
finally
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
index ebc1b27..892a46b 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -19,9 +19,14 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoderFactory;
+import org.apache.maven.surefire.providerapi.CommandListener;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
+import org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory;
import org.apache.maven.surefire.testset.TestSetFailedException;
import java.io.File;
@@ -34,6 +39,7 @@ import java.lang.reflect.InvocationTargetException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.ServiceLoader;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.Semaphore;
@@ -66,7 +72,6 @@ public final class ForkedBooter
private static final String LAST_DITCH_SHUTDOWN_THREAD = "surefire-forkedjvm-last-ditch-daemon-shutdown-thread-";
private static final String PING_THREAD = "surefire-forkedjvm-ping-";
- private final CommandReader commandReader = CommandReader.getReader();
private final ForkedChannelEncoder eventChannel = new ForkedChannelEncoder( System.out );
private volatile long systemExitTimeoutInSeconds = DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS;
@@ -74,6 +79,8 @@ public final class ForkedBooter
private ScheduledThreadPoolExecutor jvmTerminator;
private ProviderConfiguration providerConfiguration;
+ private ForkingReporterFactory forkingReporterFactory;
+ private CommandReader commandReader;
private StartupConfiguration startupConfiguration;
private Object testSet;
@@ -91,7 +98,15 @@ public final class ForkedBooter
DumpErrorSingleton.getSingleton()
.init( providerConfiguration.getReporterConfiguration().getReportsDirectory(), dumpFileName );
- startupConfiguration = booterDeserializer.getProviderConfiguration();
+ startupConfiguration = booterDeserializer.getStartupConfiguration();
+
+ forkingReporterFactory = createForkingReporterFactory();
+
+ ConsoleLogger logger = (ConsoleLogger) forkingReporterFactory.createReporter();
+ String communicationConfig = startupConfiguration.getInterProcessChannelConfiguration();
+ MasterProcessChannelDecoder decoder = lookupDecoderFactory().createDecoder( communicationConfig, logger );
+ commandReader = new CommandReader( decoder, providerConfiguration.getShutdown(), logger );
+
systemExitTimeoutInSeconds = providerConfiguration.systemExitTimeout( DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
AbstractPathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();
@@ -140,7 +155,7 @@ public final class ForkedBooter
}
else if ( readTestsFromCommandReader )
{
- return new LazyTestsToRun( eventChannel );
+ return new LazyTestsToRun( eventChannel, commandReader );
}
return null;
}
@@ -317,8 +332,7 @@ public final class ForkedBooter
private void runSuitesInProcess()
throws TestSetFailedException, InvocationTargetException
{
- ForkingReporterFactory factory = createForkingReporterFactory();
- invokeProviderInSameClassLoader( factory );
+ createProviderInCurrentClassloader( forkingReporterFactory ).invoke( testSet );
}
private ForkingReporterFactory createForkingReporterFactory()
@@ -353,15 +367,11 @@ public final class ForkedBooter
);
}
- private void invokeProviderInSameClassLoader( ForkingReporterFactory factory )
- throws TestSetFailedException, InvocationTargetException
- {
- createProviderInCurrentClassloader( factory ).invoke( testSet );
- }
-
private SurefireProvider createProviderInCurrentClassloader( ForkingReporterFactory reporterManagerFactory )
{
- BaseProviderFactory bpf = new BaseProviderFactory( reporterManagerFactory, true );
+ BaseProviderFactory bpf = new BaseProviderFactory( true );
+ bpf.setReporterFactory( reporterManagerFactory );
+ bpf.setCommandReader( commandReader );
bpf.setTestRequest( providerConfiguration.getTestSuiteDefinition() );
bpf.setReporterConfiguration( providerConfiguration.getReporterConfiguration() );
bpf.setForkedChannelEncoder( eventChannel );
@@ -373,12 +383,30 @@ public final class ForkedBooter
bpf.setDirectoryScannerParameters( providerConfiguration.getDirScannerParams() );
bpf.setMainCliOptions( providerConfiguration.getMainCliOptions() );
bpf.setSkipAfterFailureCount( providerConfiguration.getSkipAfterFailureCount() );
- bpf.setShutdown( providerConfiguration.getShutdown() );
bpf.setSystemExitTimeout( providerConfiguration.getSystemExitTimeout() );
String providerClass = startupConfiguration.getActualClassName();
return (SurefireProvider) instantiateOneArg( classLoader, providerClass, ProviderParameters.class, bpf );
}
+ private static MasterProcessChannelDecoderFactory lookupDecoderFactory()
+ {
+ MasterProcessChannelDecoderFactory defaultDecoderFactory = null;
+ MasterProcessChannelDecoderFactory customDecoderFactory = null;
+ for ( MasterProcessChannelDecoderFactory decoderFactory : ServiceLoader.load(
+ MasterProcessChannelDecoderFactory.class ) )
+ {
+ if ( decoderFactory.getClass() == DefaultMasterProcessChannelDecoderFactory.class )
+ {
+ defaultDecoderFactory = decoderFactory;
+ }
+ else
+ {
+ customDecoderFactory = decoderFactory;
+ }
+ }
+ return defaultDecoderFactory == null ? customDecoderFactory : defaultDecoderFactory;
+ }
+
/**
* This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and
* then calls the Surefire class' run method. <br> The system exit code will be 1 if an exception is thrown.
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
index 9d0b2e0..ada3384 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
@@ -25,7 +25,6 @@ import java.util.Iterator;
import org.apache.maven.surefire.util.CloseableIterator;
import org.apache.maven.surefire.util.TestsToRun;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.util.ReflectionUtils.loadClass;
/**
@@ -44,23 +43,24 @@ final class LazyTestsToRun
extends TestsToRun
{
private final ForkedChannelEncoder eventChannel;
+ private final CommandReader commandReader;
/**
* C'tor
*
* @param eventChannel the output stream to use when requesting new new tests
*/
- LazyTestsToRun( ForkedChannelEncoder eventChannel )
+ LazyTestsToRun( ForkedChannelEncoder eventChannel, CommandReader commandReader )
{
super( Collections.<Class<?>>emptySet() );
-
this.eventChannel = eventChannel;
+ this.commandReader = commandReader;
}
private final class BlockingIterator
implements Iterator<Class<?>>
{
- private final Iterator<String> it = getReader().getIterableClasses( eventChannel ).iterator();
+ private final Iterator<String> it = commandReader.getIterableClasses( eventChannel ).iterator();
@Override
public boolean hasNext()
@@ -132,7 +132,7 @@ final class LazyTestsToRun
*/
private Iterator<Class<?>> newWeakIterator()
{
- final Iterator<String> it = getReader().iterated();
+ final Iterator<String> it = commandReader.iterated();
return new CloseableIterator<Class<?>>()
{
@Override
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
index c7379e4..caa26d2 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
@@ -96,7 +96,6 @@ public class ProviderConfiguration
return reporterConfiguration;
}
-
public boolean isFailIfNoTests()
{
return failIfNoTests;
@@ -107,7 +106,6 @@ public class ProviderConfiguration
return dirScannerParams.getTestClassesDirectory();
}
-
public DirectoryScannerParameters getDirScannerParams()
{
return dirScannerParams;
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
index 870f81d..4f05025 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
@@ -48,6 +48,11 @@ public class StartupConfiguration
isInForkedVm = inForkedVm;
}
+ public String getInterProcessChannelConfiguration()
+ {
+ return "pipe:std:in";
+ }
+
public boolean isProviderMainClass()
{
return providerClassName.endsWith( "#main" );
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java
new file mode 100644
index 0000000..5c2cbe5
--- /dev/null
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoder.java
@@ -0,0 +1,160 @@
+package org.apache.maven.surefire.booter.spi;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M4
+ */
+public class DefaultMasterProcessChannelDecoder implements MasterProcessChannelDecoder
+{
+ private final InputStream is;
+ private final ConsoleLogger logger;
+
+ public DefaultMasterProcessChannelDecoder( InputStream is, ConsoleLogger logger )
+ {
+ this.is = is;
+ this.logger = logger;
+ }
+
+ protected boolean hasData( String opcode )
+ {
+ MasterProcessCommand cmd = MasterProcessCommand.byOpcode( opcode );
+ return cmd == null || cmd.hasDataType();
+ }
+
+ @Override
+ public Command decode() throws IOException
+ {
+ List<String> tokens = new ArrayList<>();
+ StringBuilder frame = new StringBuilder();
+ boolean frameStarted = false;
+ boolean frameFinished = false;
+ for ( int r; ( r = is.read() ) != -1 ; )
+ {
+ char c = (char) r;
+ if ( frameFinished && c == '\n' )
+ {
+ continue;
+ }
+
+ if ( !frameStarted )
+ {
+ if ( c == ':' )
+ {
+ frameStarted = true;
+ frameFinished = false;
+ frame.setLength( 0 );
+ tokens.clear();
+ continue;
+ }
+ }
+ else if ( !frameFinished )
+ {
+ boolean isFinishedFrame = c == ':' && isTokenComplete( tokens ) || c == '\n' || c == '\r';
+ if ( isFinishedFrame || c == ':' )
+ {
+ tokens.add( frame.toString() );
+ frame.setLength( 0 );
+ if ( isFinishedFrame )
+ {
+ frameFinished = true;
+ frameStarted = false;
+ break;
+ }
+ }
+ else
+ {
+ frame.append( c );
+ }
+ }
+
+ boolean removed = removeUnsynchronizedTokens( tokens, logger );
+ if ( removed && tokens.isEmpty() )
+ {
+ frameStarted = false;
+ frameFinished = true;
+ }
+ }
+
+ if ( tokens.size() <= 1 )
+ {
+ throw new MasterProcessCommandNoMagicNumberException( frame.toString() );
+ }
+ if ( tokens.size() == 2 )
+ {
+ return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ) );
+ }
+ else if ( tokens.size() == 3 )
+ {
+ return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ), tokens.get( 2 ) );
+ }
+ else
+ {
+ throw new MasterProcessUnknownCommandException( frame.toString() );
+ }
+ }
+
+ private boolean isTokenComplete( List<String> tokens )
+ {
+ if ( tokens.size() >= 2 )
+ {
+ return hasData( tokens.get( 1 ) ) == ( tokens.size() == 3 );
+ }
+ return false;
+ }
+
+ private boolean removeUnsynchronizedTokens( Collection<String> tokens, ConsoleLogger logger )
+ {
+ boolean removed = false;
+ for ( Iterator<String> it = tokens.iterator(); it.hasNext(); )
+ {
+ String token = it.next();
+ if ( token.equals( "maven-surefire-std-out" ) )
+ {
+ break;
+ }
+ removed = true;
+ it.remove();
+ logger.error( "Forked JVM could not synchronize the '" + token + "' token with preamble sequence." );
+ }
+ return removed;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
similarity index 51%
copy from surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
copy to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
index ff731c4..f7e7911 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/DefaultMasterProcessChannelDecoderFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,26 +19,28 @@ package org.apache.maven.surefire.booter;
* 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.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory;
+
+import java.io.IOException;
/**
- * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
*
- * @author Tibor Digana (tibor17)
- * @since 2.19
*/
-public class JUnit4SuiteTest extends TestCase
+public class DefaultMasterProcessChannelDecoderFactory
+ implements MasterProcessChannelDecoderFactory
{
- public static Test suite()
+ @Override
+ public MasterProcessChannelDecoder createDecoder( String channelConfig, ConsoleLogger logger ) throws IOException
{
- TestSuite suite = new TestSuite();
- suite.addTest( new JUnit4TestAdapter( PpidCheckerTest.class ) );
- suite.addTest( new JUnit4TestAdapter( SystemUtilsTest.class ) );
- suite.addTestSuite( ClasspathTest.class );
- suite.addTestSuite( PropertiesWrapperTest.class );
- return suite;
+ if ( "pipe:std:in".equals( channelConfig ) )
+ {
+ return new DefaultMasterProcessChannelDecoder( System.in, logger );
+ }
+ else
+ {
+ throw new IOException( "Unknown chanel configuration string " + channelConfig );
+ }
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
similarity index 65%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java
rename to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
index 0bfcdb8..261969e 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ShutdownAware.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,20 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+
+import java.io.IOException;
+
/**
- * See the plugin configuration parameter {@code shutdown}.
+ * No magic number recognized in the command line, see the JavaDoc in {@link MasterProcessCommand}.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-public interface ShutdownAware
+public class MasterProcessCommandNoMagicNumberException extends IOException
{
- void setShutdown( Shutdown shutdown );
+ MasterProcessCommandNoMagicNumberException( String line )
+ {
+ super( "No magic # recognized in the line '" + line + "'" );
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
similarity index 63%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java
rename to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
index 994b60d..11cab97 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/FailFastAware.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.booter.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,21 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+
+import java.io.IOException;
+
/**
- * See the plugin configuration parameter {@code skipAfterFailureCount}.
+ * No {@link MasterProcessCommand command} recognized according to the opcode
+ * encapsulated in the command line, see the JavaDoc in {@link MasterProcessCommand}.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface FailFastAware
+public class MasterProcessUnknownCommandException extends IOException
{
- void setSkipAfterFailureCount( int skipAfterFailureCount );
+ MasterProcessUnknownCommandException( String line )
+ {
+ super( "Unrecognized command found '" + line + "'" );
+ }
}
diff --git a/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory b/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory
new file mode 100644
index 0000000..41c6342
--- /dev/null
+++ b/surefire-booter/src/main/resources/META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelDecoderFactory
@@ -0,0 +1 @@
+org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoderFactory
\ No newline at end of file
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
similarity index 85%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 5168d2b..8c10a0c 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -19,6 +19,10 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
import org.junit.After;
import org.junit.Before;
@@ -29,7 +33,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
@@ -39,8 +42,7 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
+import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -58,7 +60,6 @@ import static org.fest.assertions.Assertions.assertThat;
public class CommandReaderTest
{
private final BlockingQueue<Byte> blockingStream = new LinkedBlockingQueue<>();
- private InputStream realInputStream;
private CommandReader reader;
static class A {
@@ -76,18 +77,19 @@ public class CommandReaderTest
@Before
public void init()
{
+ //noinspection ResultOfMethodCallIgnored
Thread.interrupted();
- realInputStream = System.in;
+ InputStream realInputStream = new SystemInputStream();
addTestToPipeline( getClass().getName() );
- System.setIn( new SystemInputStream() );
- reader = CommandReader.getReader();
+ ConsoleLogger logger = new NullConsoleLogger();
+ MasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( realInputStream, logger );
+ reader = new CommandReader( decoder, Shutdown.DEFAULT, logger );
}
@After
public void deinit()
{
reader.stop();
- System.setIn( realInputStream );
}
@Test
@@ -135,7 +137,7 @@ public class CommandReaderTest
assertThat( it1.next(), is( A.class.getName() ) );
addTestToPipeline( B.class.getName() );
- TimeUnit.MILLISECONDS.sleep( 200 ); // give the test chance to fail
+ TimeUnit.MILLISECONDS.sleep( 200L ); // give the test chance to fail
Iterator<String> it2 = reader.iterated();
@@ -240,27 +242,19 @@ public class CommandReaderTest
private void addTestToPipeline( String cls )
{
- byte[] clazz = cls.getBytes( ISO_8859_1 );
- ByteBuffer buffer = ByteBuffer.allocate( 8 + clazz.length )
- .putInt( MasterProcessCommand.RUN_CLASS.getId() )
- .putInt( clazz.length )
- .put( clazz );
- buffer.rewind();
- for ( ; buffer.hasRemaining(); )
+ String cmd = ":maven-surefire-std-out:" + MasterProcessCommand.RUN_CLASS.getOpcode() + ':' + cls + '\n';
+ for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
{
- blockingStream.add( buffer.get() );
+ blockingStream.add( cmdByte );
}
}
private void addEndOfPipeline()
{
- ByteBuffer buffer = ByteBuffer.allocate( 8 )
- .putInt( MasterProcessCommand.TEST_SET_FINISHED.getId() )
- .putInt( 0 );
- buffer.rewind();
- for ( ; buffer.hasRemaining(); )
+ String cmd = ":maven-surefire-std-out:" + MasterProcessCommand.TEST_SET_FINISHED.getOpcode() + '\n';
+ for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
{
- blockingStream.add( buffer.get() );
+ blockingStream.add( cmdByte );
}
}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
similarity index 80%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
index ccb01e3..4e4d1b2 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-
import java.util.Map;
import org.apache.maven.surefire.report.ReporterConfiguration;
import org.apache.maven.surefire.testset.DirectoryScannerParameters;
@@ -30,27 +29,28 @@ import org.apache.maven.surefire.testset.TestRequest;
/**
* @author Kristian Rosenvold
*/
-public class Foo
- implements DirectoryScannerParametersAware, TestRequestAware, ProviderPropertiesAware, ReporterConfigurationAware,
- SurefireClassLoadersAware, TestArtifactInfoAware, RunOrderParametersAware
+public class Foo extends BaseProviderFactory
{
- DirectoryScannerParameters directoryScannerParameters;
+ private DirectoryScannerParameters directoryScannerParameters;
- Map<String, String> providerProperties;
+ private Map<String, String> providerProperties;
- ReporterConfiguration reporterConfiguration;
+ private ReporterConfiguration reporterConfiguration;
- ClassLoader surefireClassLoader;
+ private ClassLoader testClassLoader;
- ClassLoader testClassLoader;
+ private TestRequest testRequest;
- TestRequest testRequest;
+ private TestArtifactInfo testArtifactInfo;
- TestArtifactInfo testArtifactInfo;
+ private RunOrderParameters runOrderParameters;
- RunOrderParameters runOrderParameters;
+ private boolean called;
- boolean called = false;
+ Foo()
+ {
+ super( false );
+ }
@Override
public void setDirectoryScannerParameters( DirectoryScannerParameters directoryScanner )
@@ -59,7 +59,6 @@ public class Foo
this.called = true;
}
-
/**
* @return true if it has been called
*/
@@ -86,7 +85,6 @@ public class Foo
public void setClassLoaders( ClassLoader testClassLoader )
{
this.testClassLoader = testClassLoader;
- this.surefireClassLoader = surefireClassLoader;
this.called = true;
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
index ff731c4..caea335 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
@@ -35,6 +35,9 @@ public class JUnit4SuiteTest extends TestCase
public static Test suite()
{
TestSuite suite = new TestSuite();
+ suite.addTest( new JUnit4TestAdapter( CommandReaderTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( MasterProcessCommandTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( SurefireReflectorTest.class ) );
suite.addTest( new JUnit4TestAdapter( PpidCheckerTest.class ) );
suite.addTest( new JUnit4TestAdapter( SystemUtilsTest.class ) );
suite.addTestSuite( ClasspathTest.class );
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
new file mode 100644
index 0000000..623c90b
--- /dev/null
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/MasterProcessCommandTest.java
@@ -0,0 +1,148 @@
+package org.apache.maven.surefire.booter;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.TestCase;
+import org.apache.maven.surefire.booter.spi.DefaultMasterProcessChannelDecoder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.apache.maven.surefire.booter.MasterProcessCommand.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.19
+ */
+public class MasterProcessCommandTest
+ extends TestCase
+{
+ public void testDataToByteArrayAndBack() throws IOException
+ {
+ for ( MasterProcessCommand commandType : MasterProcessCommand.values() )
+ {
+ switch ( commandType )
+ {
+ case RUN_CLASS:
+ assertEquals( String.class, commandType.getDataType() );
+ byte[] encoded = commandType.encode( "pkg.Test" );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:run-testclass:pkg.Test" );
+ byte[] line = addNL( encoded, '\n' );
+ InputStream is = new ByteArrayInputStream( line );
+ DefaultMasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertThat( command.getData(), is( "pkg.Test" ) );
+ break;
+ case TEST_SET_FINISHED:
+ assertThat( commandType ).isSameAs( Command.TEST_SET_FINISHED.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:testset-finished" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case SKIP_SINCE_NEXT_TEST:
+ assertThat( commandType ).isSameAs( Command.SKIP_SINCE_NEXT_TEST.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:skip-since-next-test" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case SHUTDOWN:
+ assertEquals( String.class, commandType.getDataType() );
+ encoded = commandType.encode( Shutdown.EXIT.name() );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:shutdown:EXIT" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertThat( command.getData(), is( "EXIT" ) );
+ break;
+ case NOOP:
+ assertThat( commandType ).isSameAs( Command.NOOP.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:noop" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ case BYE_ACK:
+ assertThat( commandType ).isSameAs( Command.BYE_ACK.getCommandType() );
+ assertEquals( Void.class, commandType.getDataType() );
+ encoded = commandType.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-std-out:bye-ack" );
+ is = new ByteArrayInputStream( encoded );
+ decoder = new DefaultMasterProcessChannelDecoder( is, null );
+ command = decoder.decode();
+ assertThat( command.getCommandType(), is( commandType ) );
+ assertNull( command.getData() );
+ break;
+ default:
+ fail();
+ }
+ }
+ }
+
+ public void testShouldDecodeTwoCommands() throws IOException
+ {
+ String cmd = ":maven-surefire-std-out:bye-ack\n:maven-surefire-std-out:bye-ack:";
+ InputStream is = new ByteArrayInputStream( cmd.getBytes() );
+ DefaultMasterProcessChannelDecoder decoder = new DefaultMasterProcessChannelDecoder( is, null );
+
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isEqualTo( BYE_ACK );
+ assertThat( command.getData() ).isNull();
+
+ command = decoder.decode();
+ assertThat( command.getCommandType() ).isEqualTo( BYE_ACK );
+ assertThat( command.getData() ).isNull();
+ }
+
+ private static byte[] addNL( byte[] encoded, char... newLines )
+ {
+ byte[] line = new byte[encoded.length + newLines.length];
+ System.arraycopy( encoded, 0, line, 0, encoded.length );
+ for ( int i = encoded.length, j = 0; i < line.length; i++, j++ )
+ {
+ line[i] = (byte) newLines[j];
+ }
+ return line;
+ }
+}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
similarity index 100%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
similarity index 100%
rename from surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
rename to surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannel.java
similarity index 51%
copy from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
copy to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannel.java
index eddebed..ee6ee2f 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannel.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,37 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
-
-import java.util.List;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
/**
- * CLI options in plugin (main) JVM process.
+ * 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)]*
+ *
+ * The command must be finished by New Line or the character ':'.
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public abstract class ForkedChannel
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private volatile String channelConfig;
+
+ public String getChannelConfig()
+ {
+ return channelConfig;
+ }
+
+ public void setChannelConfig( String channelConfig )
+ {
+ this.channelConfig = channelConfig;
+ }
+
+ public abstract byte[] encode( MasterProcessCommand command );
+ public abstract byte[] encode( MasterProcessCommand command, String data );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannelServer.java
similarity index 60%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
rename to surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannelServer.java
index eddebed..970278c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MainCliOptionsAware.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkedChannelServer.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,31 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.booter.Command;
-import java.util.List;
+import java.io.IOException;
/**
- * CLI options in plugin (main) JVM process.
- *
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.19
+ * @since 3.0.0-M4
*/
-interface MainCliOptionsAware
+public abstract class ForkedChannelServer
+ implements AutoCloseable
{
- void setMainCliOptions( List<CommandLineOption> mainCliOptions );
+ private final String channelConfig;
+
+ public ForkedChannelServer( String channelConfig )
+ {
+ this.channelConfig = channelConfig;
+ }
+
+ protected String getChannelConfig()
+ {
+ return channelConfig;
+ }
+
+ public abstract void send( Command command ) throws IOException;
+
+ @Override
+ public abstract void close() throws IOException;
}
diff --git a/surefire-extensions-spi/pom.xml b/surefire-extensions-spi/pom.xml
new file mode 100644
index 0000000..9738e6d
--- /dev/null
+++ b/surefire-extensions-spi/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>surefire-extensions-spi</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
similarity index 57%
rename from surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
rename to surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
index cefeb33..5b08d4d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DirectoryScannerParametersAware.java
+++ b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelDecoderFactory.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.booter;
+package org.apache.maven.surefire.spi;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,12 +19,22 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.testset.DirectoryScannerParameters;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+
+import java.io.IOException;
/**
- * @author Kristian Rosenvold
+ * The SPI interface, a factory of decoders.
*/
-interface DirectoryScannerParametersAware
+public interface MasterProcessChannelDecoderFactory
{
- void setDirectoryScannerParameters( DirectoryScannerParameters directoryScanner );
+ /**
+ * Decoder factory method.
+ *
+ * @param channelConfig "pipe:std:in" or "tcp://localhost:65035"
+ * @param logger error logger
+ * @return a new instance of decoder
+ */
+ MasterProcessChannelDecoder createDecoder( String channelConfig, ConsoleLogger logger ) throws IOException;
}
diff --git a/surefire-providers/pom.xml b/surefire-providers/pom.xml
index ad66f38..3d5cf3e 100644
--- a/surefire-providers/pom.xml
+++ b/surefire-providers/pom.xml
@@ -44,6 +44,7 @@
<module>surefire-junit-platform</module>
<module>surefire-testng-utils</module>
<module>surefire-testng</module>
+ <module>surefire-provider-api</module>
</modules>
<dependencies>
diff --git a/surefire-providers/surefire-junit-platform/pom.xml b/surefire-providers/surefire-junit-platform/pom.xml
index 823885f..354fa7c 100644
--- a/surefire-providers/surefire-junit-platform/pom.xml
+++ b/surefire-providers/surefire-junit-platform/pom.xml
@@ -83,6 +83,11 @@
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-provider-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
<artifactId>common-java5</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/surefire-providers/surefire-junit3/pom.xml b/surefire-providers/surefire-junit3/pom.xml
index d38b312..8da4a26 100644
--- a/surefire-providers/surefire-junit3/pom.xml
+++ b/surefire-providers/surefire-junit3/pom.xml
@@ -43,6 +43,11 @@
<artifactId>common-junit3</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-provider-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
diff --git a/surefire-providers/surefire-junit4/pom.xml b/surefire-providers/surefire-junit4/pom.xml
index fc4d450..7a32b19 100644
--- a/surefire-providers/surefire-junit4/pom.xml
+++ b/surefire-providers/surefire-junit4/pom.xml
@@ -43,6 +43,11 @@
<artifactId>common-junit4</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-provider-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
index b964933..9e5efad 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.junit4;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
import org.apache.maven.surefire.common.junit4.JUnit4TestChecker;
import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
@@ -52,7 +52,6 @@ import java.util.Set;
import static java.lang.reflect.Modifier.isAbstract;
import static java.lang.reflect.Modifier.isInterface;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.createMatchAnyDescriptionFilter;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
@@ -92,14 +91,14 @@ public class JUnit4Provider
private final int rerunFailingTestsCount;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public JUnit4Provider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
scanResult = bootParams.getScanResult();
diff --git a/surefire-providers/surefire-junit47/pom.xml b/surefire-providers/surefire-junit47/pom.xml
index d08b0b4..c958201 100644
--- a/surefire-providers/surefire-junit47/pom.xml
+++ b/surefire-providers/surefire-junit47/pom.xml
@@ -34,6 +34,11 @@
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-provider-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
<artifactId>common-junit48</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
index 7c74e8b..daabb60 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.junitcore;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
import org.apache.maven.surefire.common.junit4.Notifier;
@@ -46,7 +46,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
@@ -82,14 +81,14 @@ public class JUnitCoreProvider
private final TestListResolver testResolver;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public JUnitCoreProvider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
scanResult = bootParams.getScanResult();
diff --git a/surefire-providers/surefire-testng/pom.xml b/surefire-providers/surefire-testng/pom.xml
index df1bf4f..4023e0f 100644
--- a/surefire-providers/surefire-testng/pom.xml
+++ b/surefire-providers/surefire-testng/pom.xml
@@ -33,6 +33,11 @@
<dependencies>
<dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-provider-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
index 14e103a..a8a5fb7 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGProvider.java
@@ -20,8 +20,8 @@ package org.apache.maven.surefire.testng;
*/
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.CommandListener;
-import org.apache.maven.surefire.booter.CommandReader;
+import org.apache.maven.surefire.providerapi.CommandChainReader;
+import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.providerapi.AbstractProvider;
import org.apache.maven.surefire.providerapi.ProviderParameters;
@@ -43,7 +43,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
-import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
import static org.apache.maven.surefire.testset.TestListResolver.getEmptyTestListResolver;
import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
@@ -71,14 +70,14 @@ public class TestNGProvider
private final List<CommandLineOption> mainCliOptions;
- private final CommandReader commandsReader;
+ private final CommandChainReader commandsReader;
private TestsToRun testsToRun;
public TestNGProvider( ProviderParameters bootParams )
{
// don't start a thread in CommandReader while we are in in-plugin process
- commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
+ commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
providerParameters = bootParams;
testClassLoader = bootParams.getTestClassLoader();
runOrderCalculator = bootParams.getRunOrderCalculator();