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/03/07 23:36:36 UTC
[maven-surefire] 01/01: [SUREFIRE-1222] ForkClient attempts to
consume unrelated lines
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch SUREFIRE-1222
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit 29b4e0f2cdaf3962204acdf8c42ee71d43a4d1dd
Author: Tibor17 <ti...@apache.org>
AuthorDate: Thu Aug 3 14:47:49 2017 +0200
[SUREFIRE-1222] ForkClient attempts to consume unrelated lines
---
.../plugin/surefire/AbstractSurefireMojo.java | 5 +-
.../plugin/surefire/booterclient/ForkStarter.java | 9 +-
.../surefire/booterclient/output/ErrorInFork.java | 53 +-
.../surefire/booterclient/output/ForkClient.java | 451 +++++++------
.../booterclient/output/ForkedChannelDecoder.java | 341 ++++++++++
.../output/ForkedChannelDecoderErrorHandler.java | 20 +-
.../output/ForkedProcessBinaryEventListener.java | 22 +-
.../output/ForkedProcessEventListener.java | 20 +-
.../output/ForkedProcessExitErrorListener.java | 20 +-
.../output/ForkedProcessPropertyEventListener.java | 22 +-
.../output/ForkedProcessReportEventListener.java | 23 +-
.../ForkedProcessStackTraceEventListener.java | 20 +-
.../output/ForkedProcessStringEventListener.java | 20 +-
.../output/MultipleFailureException.java | 3 +-
.../surefire/report/ConsoleOutputFileReporter.java | 5 +-
.../surefire/report/DirectConsoleOutput.java | 18 +-
.../surefire/report/NullConsoleOutputReceiver.java | 3 +-
.../surefire/report/StatelessXmlReporter.java | 5 +-
.../plugin/surefire/report/TestSetRunListener.java | 38 +-
.../Utf8RecodingDeferredFileOutputStream.java | 5 +-
.../plugin/surefire/report/WrappedReportEntry.java | 3 +-
.../surefire/runorder/StatisticsReporter.java | 4 +-
.../maven/plugin/surefire/util/FileScanner.java | 6 +-
.../booterclient/ForkingRunListenerTest.java | 36 +-
.../plugin/surefire/booterclient/MockReporter.java | 11 +-
.../booterclient/output/ForkClientTest.java | 29 +-
.../output/ForkedChannelDecoderTest.java | 717 +++++++++++++++++++++
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 2 +
.../report/ConsoleOutputFileReporterTest.java | 4 +-
surefire-api/pom.xml | 5 +
.../maven/surefire/booter/BaseProviderFactory.java | 20 +-
.../maven/surefire/booter/CommandReader.java | 32 +-
.../surefire/booter/ForkedChannelEncoder.java | 461 +++++++++++++
.../maven/surefire/booter/ForkedProcessEvent.java | 129 ++++
.../surefire/booter/ForkingReporterFactory.java | 17 +-
.../maven/surefire/booter/ForkingRunListener.java | 312 ++-------
.../surefire/booter/MasterProcessCommand.java | 30 +-
.../surefire/providerapi/ProviderParameters.java | 3 +
.../surefire/report/ConsoleOutputCapture.java | 12 +-
.../surefire/report/ConsoleOutputReceiver.java | 6 +-
.../maven/surefire/report/ConsoleStream.java | 2 +-
.../report/DefaultDirectConsoleReporter.java | 5 -
.../apache/maven/surefire/report/RunListener.java | 9 +
.../org/apache/maven/surefire/report/RunMode.java | 53 +-
.../maven/surefire/testset/TestListResolver.java | 14 +-
.../maven/surefire/util/internal/StringUtils.java | 217 -------
.../java/org/apache/maven/JUnit4SuiteTest.java | 2 -
.../surefire/booter/ForkedChannelEncoderTest.java | 481 ++++++++++++++
.../surefire/booter/ForkingRunListenerTest.java | 2 +-
.../surefire/util/internal/StringUtilsTest.java | 96 ---
.../apache/maven/surefire/booter/Classpath.java | 2 +-
.../apache/maven/surefire/booter/ForkedBooter.java | 63 +-
.../maven/surefire/booter/LazyTestsToRun.java | 11 +-
.../maven/surefire/booter/TypeEncodedValue.java | 4 +-
.../maven/surefire/booter/CommandReaderTest.java | 10 +-
.../surefire/its/fixture/SurefireLauncher.java | 2 +-
.../surefire/log/api/ConsoleLoggerUtils.java | 5 +
.../apache/maven/surefire/junit4/MockReporter.java | 7 +
.../surefire/common/junit48/RequestedTest.java | 2 +-
.../maven/surefire/junit/JUnitTestSetTest.java | 6 +
surefire-providers/surefire-junit47/pom.xml | 2 +-
.../surefire/junitcore/ConcurrentRunListener.java | 12 +-
.../maven/surefire/junitcore/JUnitCoreWrapper.java | 2 +-
.../maven/surefire/junitcore/LogicalStream.java | 24 +-
.../junitcore/NonConcurrentRunListener.java | 4 +-
.../maven/surefire/junitcore/TestMethod.java | 4 +-
.../testng/utils/GroupMatcherMethodSelector.java | 14 +-
67 files changed, 2741 insertions(+), 1256 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 16c25ec..23c3642 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -232,6 +232,7 @@ public abstract class AbstractSurefireMojo
* being tested. This directory is declared by the parameter <code>testClassesDirectory</code> which defaults
* to the POM property <code>${project.build.testOutputDirectory}</code>, typically <em>src/test/java</em>
* unless overridden.
+ * //todo use regex for fully qualified class names and change the filtering abilities
*/
@Parameter
// TODO use regex for fully qualified class names in 3.0 and change the filtering abilities
@@ -1260,7 +1261,7 @@ public abstract class AbstractSurefireMojo
protected boolean isAnyConcurrencySelected()
{
- return this.getParallel() != null && this.getParallel().trim().length() > 0;
+ return getParallel() != null && !getParallel().trim().isEmpty();
}
protected boolean isAnyGroupsSelected()
@@ -1821,7 +1822,7 @@ public abstract class AbstractSurefireMojo
if ( item != null )
{
item = item.trim();
- if ( item.length() != 0 )
+ if ( !item.isEmpty() )
{
result.add( item );
}
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 b3a3f91..272f082 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
@@ -27,6 +27,7 @@ import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.Notifiable
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
+import org.apache.maven.plugin.surefire.booterclient.output.ErrorInFork;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
import org.apache.maven.plugin.surefire.booterclient.output.NativeStdErrStreamConsumer;
@@ -46,7 +47,6 @@ import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
import org.apache.maven.surefire.booter.SurefireExecutionException;
import org.apache.maven.surefire.providerapi.SurefireProvider;
-import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.testset.TestRequest;
import org.apache.maven.surefire.util.DefaultScanResult;
@@ -660,12 +660,13 @@ public class ForkStarter
if ( forkClient.isErrorInFork() )
{
- StackTraceWriter errorInFork = forkClient.getErrorInFork();
- // noinspection ThrowFromFinallyBlock
+ ErrorInFork errorInFork = forkClient.getErrorInFork();
+ //todo boolean showStackTrace = providerConfiguration.getMainCliOptions().contains( SHOW_ERRORS );
+ //noinspection ThrowFromFinallyBlock
throw new SurefireBooterForkException( "There was an error in the forked process"
+ detail
+ '\n'
- + errorInFork.getThrowable().getLocalizedMessage(), cause );
+ + errorInFork, cause );
}
if ( !forkClient.isSaidGoodBye() )
{
diff --git a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ErrorInFork.java
similarity index 50%
copy from surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ErrorInFork.java
index 7eca90b..cd851f6 100644
--- a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ErrorInFork.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire.log.api;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,37 +19,50 @@ package org.apache.maven.plugin.surefire.log.api;
* under the License.
*/
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
/**
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20
+ * @since 2.20.1
*/
-public final class ConsoleLoggerUtils
+public final class ErrorInFork
{
- private ConsoleLoggerUtils()
+ private final String localizedMessage;
+ private final String stackTrace;
+
+ public ErrorInFork( String localizedMessage, String stackTrace )
+ {
+ this.localizedMessage = localizedMessage;
+ this.stackTrace = stackTrace;
+ }
+
+ public String getLocalizedMessage()
+ {
+ return localizedMessage;
+ }
+
+ public String getStackTrace()
{
- throw new IllegalStateException( "non instantiable constructor" );
+ return stackTrace;
}
- public static String toString( String message, Throwable t )
+ @Override
+ public String toString()
{
- StringWriter result = new StringWriter( 512 );
- PrintWriter writer = new PrintWriter( result );
- try
+ StringBuilder builder = new StringBuilder();
+ if ( isNotBlank( localizedMessage ) )
{
- if ( message != null )
- {
- writer.println( message );
- }
- t.printStackTrace( writer );
- writer.flush();
- return result.toString();
+ builder.append( localizedMessage );
}
- finally
+
+ if ( isNotBlank( stackTrace ) )
{
- writer.close();
+ if ( builder.length() != 0 )
+ {
+ builder.append( '\n' );
+ }
+ builder.append( stackTrace );
}
+ return super.toString();
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
index 583460f..124d0c7 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -26,46 +26,22 @@ import org.apache.maven.shared.utils.cli.StreamConsumer;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
-import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.RunMode;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
-import java.nio.ByteBuffer;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
-import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
-import static java.lang.Integer.decode;
import static java.lang.System.currentTimeMillis;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_BYE;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_CONSOLE;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_DEBUG;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_ERROR;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_NEXT_TEST;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STDERR;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STDOUT;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STOP_ON_NEXT_TEST;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_SYSPROPS;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_STARTING;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_ERROR;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_FAILED;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_SKIPPED;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_STARTING;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_SUCCEEDED;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_WARNING;
import static org.apache.maven.surefire.booter.Shutdown.KILL;
-import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
-import static org.apache.maven.surefire.util.internal.StringUtils.unescapeBytes;
-import static org.apache.maven.surefire.util.internal.StringUtils.unescapeString;
// todo move to the same package with ForkStarter
@@ -90,17 +66,21 @@ public class ForkClient
/**
* <t>testSetStartedAt</t> is set to non-zero after received
- * {@link org.apache.maven.surefire.booter.ForkingRunListener#BOOTERCODE_TESTSET_STARTING test-set}.
+ * {@link org.apache.maven.surefire.booter.ForkedChannelEncoder#testSetStarting(ReportEntry, boolean)}.
*/
private final AtomicLong testSetStartedAt = new AtomicLong( START_TIME_ZERO );
+ private final ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+
private final ConsoleLogger log;
+ private final ForkedChannelDecoderErrorHandler errorHandler;
+
private RunListener testSetReporter;
private volatile boolean saidGoodBye;
- private volatile StackTraceWriter errorInFork;
+ private volatile ErrorInFork errorInFork;
private volatile int forkNumber;
@@ -114,6 +94,211 @@ public class ForkClient
this.testVmSystemProperties = testVmSystemProperties;
this.notifiableTestStream = notifiableTestStream;
this.log = log;
+ decoder.setTestSetStartingListener( new TestSetStartingListener() );
+ decoder.setTestSetCompletedListener( new TestSetCompletedListener() );
+ decoder.setTestStartingListener( new TestStartingListener() );
+ decoder.setTestSucceededListener( new TestSucceededListener() );
+ decoder.setTestFailedListener( new TestFailedListener() );
+ decoder.setTestSkippedListener( new TestSkippedListener() );
+ decoder.setTestErrorListener( new TestErrorListener() );
+ decoder.setTestAssumptionFailureListener( new TestAssumptionFailureListener() );
+ decoder.setSystemPropertiesListener( new SystemPropertiesListener() );
+ decoder.setStdOutListener( new StdOutListener() );
+ decoder.setStdErrListener( new StdErrListener() );
+ decoder.setConsoleInfoListener( new ConsoleListener() );
+ decoder.setAcquireNextTestListener( new AcquireNextTestListener() );
+ decoder.setConsoleErrorListener( new ErrorListener() );
+ decoder.setByeListener( new ByeListener() );
+ decoder.setStopOnNextTestListener( new StopOnNextTestListener() );
+ decoder.setConsoleDebugListener( new DebugListener() );
+ decoder.setConsoleWarningListener( new WarningListener() );
+ errorHandler = new ErrorHandler();
+ }
+
+ private final class ErrorHandler implements ForkedChannelDecoderErrorHandler
+ {
+ @Override
+ public void handledError( String line, Throwable e )
+ {
+ logStreamWarning( line, e );
+ }
+ }
+
+ private final class TestSetStartingListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ getTestSetReporter().testSetStarting( reportEntry );
+ setCurrentStartTime();
+ }
+ }
+
+ private final class TestSetCompletedListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.clear();
+ getTestSetReporter().testSetCompleted( reportEntry );
+ }
+ }
+
+ private final class TestStartingListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.offer( reportEntry.getSourceName() );
+ getTestSetReporter().testStarting( reportEntry );
+ }
+ }
+
+ private final class TestSucceededListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.remove( reportEntry.getSourceName() );
+ getTestSetReporter().testSucceeded( reportEntry );
+ }
+ }
+
+ private final class TestFailedListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.remove( reportEntry.getSourceName() );
+ getTestSetReporter().testFailed( reportEntry );
+ }
+ }
+
+ private final class TestSkippedListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.remove( reportEntry.getSourceName() );
+ getTestSetReporter().testSkipped( reportEntry );
+ }
+ }
+
+ private final class TestErrorListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.remove( reportEntry.getSourceName() );
+ getTestSetReporter().testError( reportEntry );
+ }
+ }
+
+ private final class TestAssumptionFailureListener implements ForkedProcessReportEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ testsInProgress.remove( reportEntry.getSourceName() );
+ getTestSetReporter().testAssumptionFailure( reportEntry );
+ }
+ }
+
+ private final class SystemPropertiesListener implements ForkedProcessPropertyEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, String key, String value )
+ {
+ synchronized ( testVmSystemProperties )
+ {
+ testVmSystemProperties.put( key, value );
+ }
+ }
+ }
+
+ private final class StdOutListener implements ForkedProcessBinaryEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, String output )
+ {
+ writeTestOutput( output, true );
+ }
+ }
+
+ private final class StdErrListener implements ForkedProcessBinaryEventListener
+ {
+ @Override
+ public void handle( RunMode runMode, String output )
+ {
+ writeTestOutput( output, false );
+ }
+ }
+
+ private final class ConsoleListener implements ForkedProcessStringEventListener
+ {
+ @Override
+ public void handle( String msg )
+ {
+ getOrCreateConsoleLogger()
+ .info( msg );
+ }
+ }
+
+ private final class AcquireNextTestListener implements ForkedProcessEventListener
+ {
+ @Override
+ public void handle()
+ {
+ notifiableTestStream.provideNewTest();
+ }
+ }
+
+ private class ErrorListener implements ForkedProcessStackTraceEventListener
+ {
+ @Override
+ public void handle( String msg, String smartStackTrace, String stackTrace )
+ {
+ errorInFork = new ErrorInFork( msg, stackTrace );
+ }
+ }
+
+ private final class ByeListener implements ForkedProcessEventListener
+ {
+ @Override
+ public void handle()
+ {
+ saidGoodBye = true;
+ notifiableTestStream.acknowledgeByeEventReceived();
+ }
+ }
+
+ private final class StopOnNextTestListener implements ForkedProcessEventListener
+ {
+ @Override
+ public void handle()
+ {
+ stopOnNextTest();
+ }
+ }
+
+ private final class DebugListener implements ForkedProcessStringEventListener
+ {
+ @Override
+ public void handle( String msg )
+ {
+ getOrCreateConsoleLogger()
+ .debug( msg );
+ }
+ }
+
+ private final class WarningListener implements ForkedProcessStringEventListener
+ {
+ @Override
+ public void handle( String msg )
+ {
+ getOrCreateConsoleLogger()
+ .warning( msg );
+ }
}
protected void stopOnNextTest()
@@ -184,117 +369,10 @@ public class ForkClient
private void processLine( String event )
{
- final OperationalData op;
- try
- {
- op = new OperationalData( event );
- }
- catch ( RuntimeException e )
- {
- logStreamWarning( e, event );
- return;
- }
- final String remaining = op.getData();
- switch ( op.getOperationId() )
- {
- case BOOTERCODE_TESTSET_STARTING:
- getTestSetReporter().testSetStarting( createReportEntry( remaining ) );
- setCurrentStartTime();
- break;
- case BOOTERCODE_TESTSET_COMPLETED:
- testsInProgress.clear();
-
- getTestSetReporter().testSetCompleted( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_STARTING:
- ReportEntry reportEntry = createReportEntry( remaining );
- testsInProgress.offer( reportEntry.getSourceName() );
-
- getTestSetReporter().testStarting( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_SUCCEEDED:
- reportEntry = createReportEntry( remaining );
- testsInProgress.remove( reportEntry.getSourceName() );
-
- getTestSetReporter().testSucceeded( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_FAILED:
- reportEntry = createReportEntry( remaining );
- testsInProgress.remove( reportEntry.getSourceName() );
-
- getTestSetReporter().testFailed( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_SKIPPED:
- reportEntry = createReportEntry( remaining );
- testsInProgress.remove( reportEntry.getSourceName() );
-
- getTestSetReporter().testSkipped( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_ERROR:
- reportEntry = createReportEntry( remaining );
- testsInProgress.remove( reportEntry.getSourceName() );
-
- getTestSetReporter().testError( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
- reportEntry = createReportEntry( remaining );
- testsInProgress.remove( reportEntry.getSourceName() );
-
- getTestSetReporter().testAssumptionFailure( createReportEntry( remaining ) );
- break;
- case BOOTERCODE_SYSPROPS:
- int keyEnd = remaining.indexOf( "," );
- StringBuilder key = new StringBuilder();
- StringBuilder value = new StringBuilder();
- unescapeString( key, remaining.substring( 0, keyEnd ) );
- unescapeString( value, remaining.substring( keyEnd + 1 ) );
- synchronized ( testVmSystemProperties )
- {
- testVmSystemProperties.put( key.toString(), value.toString() );
- }
- break;
- case BOOTERCODE_STDOUT:
- writeTestOutput( remaining, true );
- break;
- case BOOTERCODE_STDERR:
- writeTestOutput( remaining, false );
- break;
- case BOOTERCODE_CONSOLE:
- getOrCreateConsoleLogger()
- .info( createConsoleMessage( remaining ) );
- break;
- case BOOTERCODE_NEXT_TEST:
- notifiableTestStream.provideNewTest();
- break;
- case BOOTERCODE_ERROR:
- errorInFork = deserializeStackTraceWriter( new StringTokenizer( remaining, "," ) );
- break;
- case BOOTERCODE_BYE:
- saidGoodBye = true;
- notifiableTestStream.acknowledgeByeEventReceived();
- break;
- case BOOTERCODE_STOP_ON_NEXT_TEST:
- stopOnNextTest();
- break;
- case BOOTERCODE_DEBUG:
- getOrCreateConsoleLogger()
- .debug( createConsoleMessage( remaining ) );
- break;
- case BOOTERCODE_WARNING:
- getOrCreateConsoleLogger()
- .warning( createConsoleMessage( remaining ) );
- break;
- default:
- logStreamWarning( event );
- }
- }
-
- private void logStreamWarning( String event )
- {
- logStreamWarning( null, event );
+ decoder.handleEvent( event, errorHandler );
}
- private void logStreamWarning( Throwable e, String event )
+ private void logStreamWarning( String event, Throwable e )
{
final String msg = "Corrupted stdin stream in forked JVM " + forkNumber + ".";
final InPluginProcessDumpSingleton util = InPluginProcessDumpSingleton.getSingleton();
@@ -309,26 +387,10 @@ public class ForkClient
}
}
- private void writeTestOutput( String remaining, boolean isStdout )
+ private void writeTestOutput( String output, boolean isStdout )
{
- int csNameEnd = remaining.indexOf( ',' );
- String charsetName = remaining.substring( 0, csNameEnd );
- String byteEncoded = remaining.substring( csNameEnd + 1 );
- ByteBuffer unescaped = unescapeBytes( byteEncoded, charsetName );
-
- if ( unescaped.hasArray() )
- {
- byte[] convertedBytes = unescaped.array();
- getOrCreateConsoleOutputReceiver()
- .writeTestOutput( convertedBytes, unescaped.position(), unescaped.remaining(), isStdout );
- }
- else
- {
- byte[] convertedBytes = new byte[unescaped.remaining()];
- unescaped.get( convertedBytes, 0, unescaped.remaining() );
- getOrCreateConsoleOutputReceiver()
- .writeTestOutput( convertedBytes, 0, convertedBytes.length, isStdout );
- }
+ getOrCreateConsoleOutputReceiver()
+ .writeTestOutput( output, isStdout );
}
public final void consumeMultiLineContent( String s )
@@ -341,54 +403,6 @@ public class ForkClient
}
}
- private String createConsoleMessage( String remaining )
- {
- return unescape( remaining );
- }
-
- private ReportEntry createReportEntry( String untokenized )
- {
- StringTokenizer tokens = new StringTokenizer( untokenized, "," );
- try
- {
- String source = nullableCsv( tokens.nextToken() );
- String name = nullableCsv( tokens.nextToken() );
- String group = nullableCsv( tokens.nextToken() );
- String message = nullableCsv( tokens.nextToken() );
- String elapsedStr = tokens.nextToken();
- Integer elapsed = "null".equals( elapsedStr ) ? null : decode( elapsedStr );
- final StackTraceWriter stackTraceWriter =
- tokens.hasMoreTokens() ? deserializeStackTraceWriter( tokens ) : null;
-
- return reportEntry( source, name, group, stackTraceWriter, elapsed, message );
- }
- catch ( RuntimeException e )
- {
- throw new RuntimeException( untokenized, e );
- }
- }
-
- private StackTraceWriter deserializeStackTraceWriter( StringTokenizer tokens )
- {
- String stackTraceMessage = nullableCsv( tokens.nextToken() );
- String smartStackTrace = nullableCsv( tokens.nextToken() );
- String stackTrace = tokens.hasMoreTokens() ? nullableCsv( tokens.nextToken() ) : null;
- boolean hasTrace = stackTrace != null;
- return hasTrace ? new DeserializedStacktraceWriter( stackTraceMessage, smartStackTrace, stackTrace ) : null;
- }
-
- private String nullableCsv( String source )
- {
- return "null".equals( source ) ? null : unescape( source );
- }
-
- private String unescape( String source )
- {
- StringBuilder stringBuffer = new StringBuilder( source.length() );
- unescapeString( stringBuffer, source );
- return stringBuffer.toString();
- }
-
/**
* Used when getting reporters on the plugin side of a fork.
* Used by testing purposes only. May not be volatile variable.
@@ -420,7 +434,7 @@ public class ForkClient
return saidGoodBye;
}
- public final StackTraceWriter getErrorInFork()
+ public final ErrorInFork getErrorInFork()
{
return errorInFork;
}
@@ -445,33 +459,4 @@ public class ForkClient
assert this.forkNumber == 0;
this.forkNumber = forkNumber;
}
-
- private static final class OperationalData
- {
- private final byte operationId;
- private final String data;
-
- OperationalData( String event )
- {
- operationId = (byte) event.charAt( 0 );
- int comma = event.indexOf( ",", 3 );
- if ( comma < 0 )
- {
- throw new IllegalArgumentException( "Stream stdin corrupted. Expected comma after third character "
- + "in command '" + event + "'." );
- }
- int rest = event.indexOf( ",", comma );
- data = event.substring( rest + 1 );
- }
-
- byte getOperationId()
- {
- return operationId;
- }
-
- String getData()
- {
- return data;
- }
- }
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java
new file mode 100644
index 0000000..bef3315
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoder.java
@@ -0,0 +1,341 @@
+package org.apache.maven.plugin.surefire.booterclient.output;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.booter.ForkedProcessEvent;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.StackTraceWriter;
+
+import java.nio.charset.Charset;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static javax.xml.bind.DatatypeConverter.parseBase64Binary;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.MAGIC_NUMBER;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SUCCEEDED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.EVENTS;
+import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
+import static org.apache.maven.surefire.report.RunMode.MODES;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
+import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
+
+/**
+ * magic number : opcode : run mode [: opcode specific data]*
+ * <p/>
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public final class ForkedChannelDecoder
+{
+ private static final byte[] EMPTY = {};
+
+ private volatile ForkedProcessPropertyEventListener propertyEventListener;
+ private volatile ForkedProcessStackTraceEventListener consoleErrorEventListener;
+ private volatile ForkedProcessExitErrorListener exitErrorEventListener;
+
+ private final ConcurrentMap<ForkedProcessEvent, ForkedProcessReportEventListener> reportEventListeners =
+ new ConcurrentHashMap<ForkedProcessEvent, ForkedProcessReportEventListener>();
+
+ private final ConcurrentMap<ForkedProcessEvent, ForkedProcessBinaryEventListener> binaryEventListeners =
+ new ConcurrentHashMap<ForkedProcessEvent, ForkedProcessBinaryEventListener>();
+
+ private final ConcurrentMap<ForkedProcessEvent, ForkedProcessStringEventListener> consoleEventListeners =
+ new ConcurrentHashMap<ForkedProcessEvent, ForkedProcessStringEventListener>();
+
+ private final ConcurrentMap<ForkedProcessEvent, ForkedProcessEventListener> controlEventListeners =
+ new ConcurrentHashMap<ForkedProcessEvent, ForkedProcessEventListener>();
+
+ public void setSystemPropertiesListener( ForkedProcessPropertyEventListener listener )
+ {
+ propertyEventListener = requireNonNull( listener );
+ }
+
+ public void setTestSetStartingListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TESTSET_STARTING, requireNonNull( listener ) );
+ }
+
+ public void setTestSetCompletedListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TESTSET_COMPLETED, requireNonNull( listener ) );
+ }
+
+ public void setTestStartingListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_STARTING, requireNonNull( listener ) );
+ }
+
+ public void setTestSucceededListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_SUCCEEDED, requireNonNull( listener ) );
+ }
+
+ public void setTestFailedListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_FAILED, requireNonNull( listener ) );
+ }
+
+ public void setTestSkippedListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_SKIPPED, requireNonNull( listener ) );
+ }
+
+ public void setTestErrorListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_ERROR, requireNonNull( listener ) );
+ }
+
+ public void setTestAssumptionFailureListener( ForkedProcessReportEventListener listener )
+ {
+ reportEventListeners.put( BOOTERCODE_TEST_ASSUMPTIONFAILURE, requireNonNull( listener ) );
+ }
+
+ public void setStdOutListener( ForkedProcessBinaryEventListener listener )
+ {
+ binaryEventListeners.put( BOOTERCODE_STDOUT, requireNonNull( listener ) );
+ }
+
+ public void setStdErrListener( ForkedProcessBinaryEventListener listener )
+ {
+ binaryEventListeners.put( BOOTERCODE_STDERR, requireNonNull( listener ) );
+ }
+
+ public void setConsoleInfoListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_INFO, requireNonNull( listener ) );
+ }
+
+ public void setConsoleErrorListener( ForkedProcessStackTraceEventListener listener )
+ {
+ consoleErrorEventListener = requireNonNull( listener );
+ }
+
+ public void setConsoleDebugListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_DEBUG, requireNonNull( listener ) );
+ }
+
+ public void setConsoleWarningListener( ForkedProcessStringEventListener listener )
+ {
+ consoleEventListeners.put( BOOTERCODE_CONSOLE_WARNING, requireNonNull( listener ) );
+ }
+
+ public void setByeListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_BYE, requireNonNull( listener ) );
+ }
+
+ public void setStopOnNextTestListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_STOP_ON_NEXT_TEST, requireNonNull( listener ) );
+ }
+
+ public void setAcquireNextTestListener( ForkedProcessEventListener listener )
+ {
+ controlEventListeners.put( BOOTERCODE_NEXT_TEST, requireNonNull( listener ) );
+ }
+
+ public void setExitErrorEventListener( ForkedProcessExitErrorListener listener )
+ {
+ exitErrorEventListener = requireNonNull( listener );
+ }
+
+ public void handleEvent( String line, ForkedChannelDecoderErrorHandler errorHandler )
+ {
+ if ( line == null || !line.startsWith( MAGIC_NUMBER ) )
+ {
+ errorHandler.handledError( line, null );
+ return;
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer( line.substring( MAGIC_NUMBER.length() ), ":" );
+ RunMode mode = tokenizer.hasMoreTokens() ? MODES.get( tokenizer.nextToken() ) : null;
+ String opcode = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ ForkedProcessEvent event = opcode == null ? null : EVENTS.get( opcode );
+ if ( event == null )
+ {
+ errorHandler.handledError( line, null );
+ return;
+ }
+
+ try
+ {
+ if ( event.isControlCategory() )
+ {
+ ForkedProcessEventListener listener = controlEventListeners.get( event );
+ if ( listener != null )
+ {
+ listener.handle();
+ }
+ }
+ else if ( event.isConsoleCategory() )
+ {
+ ForkedProcessStringEventListener listener = consoleEventListeners.get( event );
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ if ( listener != null && encoding != null )
+ {
+ String msg = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ listener.handle( msg );
+ }
+ }
+ else if ( event.isConsoleErrorCategory() )
+ {
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ if ( consoleErrorEventListener != null && encoding != null )
+ {
+ String msg = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : null;
+ String smartStackTrace =
+ tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : null;
+ String stackTrace = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : null;
+ consoleErrorEventListener.handle( msg, smartStackTrace, stackTrace );
+ }
+ }
+ else if ( event.isStandardStreamCategory() )
+ {
+ ForkedProcessBinaryEventListener listener = binaryEventListeners.get( event );
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ if ( listener != null && encoding != null && mode != null )
+ {
+ byte[] stream = tokenizer.hasMoreTokens() ? decodeToBytes( tokenizer.nextToken() ) : EMPTY;
+ listener.handle( mode, new String( stream, encoding ) );
+ }
+ }
+ else if ( event.isSysPropCategory() )
+ {
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ String key = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ if ( propertyEventListener != null && isNotBlank( key ) )
+ {
+ String value = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ propertyEventListener.handle( mode, key, value );
+ }
+ }
+ else if ( event.isTestCategory() )
+ {
+ ForkedProcessReportEventListener listener = reportEventListeners.get( event );
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ if ( listener != null && encoding != null && mode != null )
+ {
+ String sourceName = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String name = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String group = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String message = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String elapsed = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String traceMessage = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String smartTrimmedStackTrace = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+ String stackTrace = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+
+ listener.handle( mode, toReportEntry( encoding, sourceName, name, group, message, elapsed,
+ traceMessage, smartTrimmedStackTrace, stackTrace ) );
+ }
+ }
+ else if ( event.isJvmExitError() )
+ {
+ if ( exitErrorEventListener != null )
+ {
+ Charset encoding = tokenizer.hasMoreTokens() ? Charset.forName( tokenizer.nextToken() ) : null;
+ String message = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ String smartTrimmedStackTrace =
+ tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ String stackTrace = tokenizer.hasMoreTokens() ? decode( tokenizer.nextToken(), encoding ) : "";
+ exitErrorEventListener.handle( message, smartTrimmedStackTrace, stackTrace );
+ }
+ }
+ }
+ catch ( IllegalArgumentException e )
+ {
+ errorHandler.handledError( line, e );
+ }
+ }
+
+ static ReportEntry
+ toReportEntry( Charset encoding,
+ // ReportEntry:
+ String encSource, String encName, String encGroup, String encMessage, String encTimeElapsed,
+ // StackTraceWriter:
+ String encTraceMessage, String encSmartTrimmedStackTrace, String encStackTrace )
+ throws NumberFormatException
+ {
+ if ( encoding == null )
+ {
+ // corrupted or incomplete stream
+ return null;
+ }
+
+ String source = decode( encSource, encoding );
+ String name = decode( encName, encoding );
+ String group = decode( encGroup, encoding );
+ StackTraceWriter stackTraceWriter =
+ decodeTrace( encoding, encTraceMessage, encSmartTrimmedStackTrace, encStackTrace );
+ Integer elapsed = decodeToInteger( encTimeElapsed );
+ String message = decode( encMessage, encoding );
+ return reportEntry( source, name, group, stackTraceWriter, elapsed, message );
+ }
+
+ static String decode( String line, Charset encoding )
+ {
+ return line == null || "-".equals( line ) ? null : new String( parseBase64Binary( line ), encoding );
+ }
+
+ static Integer decodeToInteger( String line )
+ {
+ return line == null || "-".equals( line ) ? null : Integer.decode( line );
+ }
+
+ static byte[] decodeToBytes( String line )
+ {
+ return line == null || "-".equals( line ) ? null : parseBase64Binary( line );
+ }
+
+ private static StackTraceWriter decodeTrace( Charset encoding, String encTraceMessage,
+ String encSmartTrimmedStackTrace, String encStackTrace )
+ {
+ if ( isBlank( encStackTrace ) || "-".equals( encStackTrace ) )
+ {
+ return null;
+ }
+ else
+ {
+ String traceMessage = decode( encTraceMessage, encoding );
+ String stackTrace = decode( encStackTrace, encoding );
+ String smartTrimmedStackTrace = decode( encSmartTrimmedStackTrace, encoding );
+ return new DeserializedStacktraceWriter( traceMessage, smartTrimmedStackTrace, stackTrace );
+ }
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.java
index 06d6414..7a2bc9b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderErrorHandler.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,10 @@ package org.apache.maven.surefire.report;
*/
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedChannelDecoderErrorHandler
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handledError( String line, Throwable e );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessBinaryEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessBinaryEventListener.java
index 06d6414..ff65045 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessBinaryEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,13 @@ package org.apache.maven.surefire.report;
* under the License.
*/
+import org.apache.maven.surefire.report.RunMode;
+
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessBinaryEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( RunMode runMode, String output );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventListener.java
index 06d6414..450a7e1 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,10 @@ package org.apache.maven.surefire.report;
*/
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle();
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
index 06d6414..b9d88c2 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessExitErrorListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,10 @@ package org.apache.maven.surefire.report;
*/
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessExitErrorListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( String exceptionMessage, String smartTrimmedStackTrace, String stackTrace );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessPropertyEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessPropertyEventListener.java
index 06d6414..647facc 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessPropertyEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,13 @@ package org.apache.maven.surefire.report;
* under the License.
*/
+import org.apache.maven.surefire.report.RunMode;
+
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessPropertyEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( RunMode runMode, String key, String value );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
index 06d6414..476f90b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,14 @@ package org.apache.maven.surefire.report;
* under the License.
*/
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessReportEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( RunMode runMode, ReportEntry reportEntry );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
index 06d6414..641fd50 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStackTraceEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,10 @@ package org.apache.maven.surefire.report;
*/
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessStackTraceEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( String msg, String smartStackTrace, String stackTrace );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStringEventListener.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStringEventListener.java
index 06d6414..3641ba1 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStringEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,10 @@ package org.apache.maven.surefire.report;
*/
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public interface ForkedProcessStringEventListener
{
-
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
+ void handle( String msg );
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/MultipleFailureException.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/MultipleFailureException.java
index 4149ad9..f465393 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/MultipleFailureException.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/MultipleFailureException.java
@@ -58,7 +58,8 @@ final class MultipleFailureException
public String getMessage()
{
StringBuilder messages = new StringBuilder();
- for ( Throwable exception = exceptions.peek(); exception != null; exception = exceptions.peek() )
+ for ( //noinspection ThrowableResultOfMethodCallIgnored
+ Throwable exception = exceptions.peek(); exception != null; exception = exceptions.peek() )
{
if ( messages.length() != 0 )
{
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
index f9e59fe..3bb0b06 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import org.apache.maven.surefire.report.ReportEntry;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.maven.plugin.surefire.report.FileReporter.getReportFile;
/**
@@ -79,7 +80,7 @@ public class ConsoleOutputFileReporter
}
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public void writeTestOutput( String output, boolean stdout )
{
try
{
@@ -93,7 +94,7 @@ public class ConsoleOutputFileReporter
File file = getReportFile( reportsDirectory, reportEntryName, reportNameSuffix, "-output.txt" );
fileOutputStream = new FileOutputStream( file );
}
- fileOutputStream.write( buf, off, len );
+ fileOutputStream.write( output.getBytes( UTF_8 ) );
}
catch ( IOException e )
{
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java
index 25312aa..ab11c5c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java
@@ -20,14 +20,9 @@ package org.apache.maven.plugin.surefire.report;
*/
import java.io.PrintStream;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
import org.apache.maven.surefire.report.ReportEntry;
-import static java.nio.charset.Charset.defaultCharset;
-
/**
* Outputs test system out/system err directly to the console
* <p/>
@@ -50,18 +45,11 @@ public class DirectConsoleOutput
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ @Override
+ public void writeTestOutput( String output, boolean stdout )
{
final PrintStream stream = stdout ? sout : serr;
- try
- {
- CharBuffer decode = defaultCharset().newDecoder().decode( ByteBuffer.wrap( buf, off, len ) );
- stream.append( decode );
- }
- catch ( CharacterCodingException e )
- {
- stream.write( buf, off, len );
- }
+ stream.append( output );
}
public void testSetStarting( ReportEntry reportEntry )
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java
index e18f3aa..e0cd14e 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java
@@ -49,7 +49,8 @@ class NullConsoleOutputReceiver
{
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ @Override
+ public void writeTestOutput( String output, boolean stdout )
{
}
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
index 397c4c1..85788f5 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
@@ -45,6 +45,7 @@ import java.util.StringTokenizer;
import static org.apache.maven.plugin.surefire.report.DefaultReporterFactory.TestResultType;
import static org.apache.maven.plugin.surefire.report.FileReporterUtils.stripIllegalFilenameChars;
import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
+import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
// CHECKSTYLE_OFF: LineLength
/**
@@ -335,7 +336,7 @@ public class StatelessXmlReporter
}
if ( report.getSourceName() != null )
{
- if ( reportNameSuffix != null && reportNameSuffix.length() > 0 )
+ if ( isNotBlank( reportNameSuffix ) )
{
ppw.addAttribute( "classname", report.getSourceName() + "(" + reportNameSuffix + ")" );
}
@@ -381,7 +382,7 @@ public class StatelessXmlReporter
String stackTrace = report.getStackTrace( trimStackTrace );
- if ( report.getMessage() != null && report.getMessage().length() > 0 )
+ if ( isNotBlank( report.getMessage() ) )
{
ppw.addAttribute( "message", extraEscape( report.getMessage(), true ) );
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
index f0f996d..d72f9d9 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
@@ -19,21 +19,25 @@ package org.apache.maven.plugin.surefire.report;
* under the License.
*/
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.runorder.StatisticsReporter;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.maven.plugin.surefire.report.ReportEntryType.ERROR;
import static org.apache.maven.plugin.surefire.report.ReportEntryType.FAILURE;
import static org.apache.maven.plugin.surefire.report.ReportEntryType.SKIPPED;
import static org.apache.maven.plugin.surefire.report.ReportEntryType.SUCCESS;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
/**
* Reports data for a single test set.
@@ -69,6 +73,8 @@ public class TestSetRunListener
private final StatisticsReporter statisticsReporter;
+ private volatile RunMode runMode = NORMAL_RUN;
+
@SuppressWarnings( "checkstyle:parameternumber" )
public TestSetRunListener( ConsoleReporter consoleReporter, FileReporter fileReporter,
StatelessXmlReporter simpleXMLReporter,
@@ -116,24 +122,19 @@ public class TestSetRunListener
consoleReporter.getConsoleLogger().error( t );
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public void writeTestOutput( String output, boolean stdout )
{
try
{
- if ( stdout )
- {
- testStdOut.write( buf, off, len );
- }
- else
- {
- testStdErr.write( buf, off, len );
- }
+ byte[] content = output.getBytes( UTF_8 );
+ Utf8RecodingDeferredFileOutputStream stream = stdout ? testStdOut : testStdErr;
+ stream.write( content, 0, content.length );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
- consoleOutputReceiver.writeTestOutput( buf, off, len, stdout );
+ consoleOutputReceiver.writeTestOutput( output, stdout );
}
public void testSetStarting( ReportEntry report )
@@ -219,6 +220,13 @@ public class TestSetRunListener
{
}
+ public RunMode markAs( RunMode currentRunMode )
+ {
+ RunMode runMode = this.runMode;
+ this.runMode = requireNonNull( currentRunMode );
+ return runMode;
+ }
+
public void testAssumptionFailure( ReportEntry report )
{
testSkipped( report );
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/Utf8RecodingDeferredFileOutputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/Utf8RecodingDeferredFileOutputStream.java
index 954a2bb..62a7443 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/Utf8RecodingDeferredFileOutputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/Utf8RecodingDeferredFileOutputStream.java
@@ -44,7 +44,7 @@ class Utf8RecodingDeferredFileOutputStream
@SuppressWarnings( "checkstyle:magicnumber" )
public Utf8RecodingDeferredFileOutputStream( String channel )
{
- this.deferredFileOutputStream = new DeferredFileOutputStream( 1000000, channel, "deferred", null );
+ deferredFileOutputStream = new DeferredFileOutputStream( 1000000, channel, "deferred", null );
}
public synchronized void write( byte[] buf, int off, int len )
@@ -58,13 +58,14 @@ class Utf8RecodingDeferredFileOutputStream
if ( !Charset.defaultCharset().equals( UTF8 ) )
{
CharBuffer decodedFromDefaultCharset = Charset.defaultCharset().decode( ByteBuffer.wrap( buf, off, len ) );
+ //todo check encoding
ByteBuffer utf8Encoded = UTF8.encode( decodedFromDefaultCharset );
if ( utf8Encoded.hasArray() )
{
byte[] convertedBytes = utf8Encoded.array();
- deferredFileOutputStream.write( convertedBytes, utf8Encoded.position(), utf8Encoded.remaining() );
+ deferredFileOutputStream.write( convertedBytes, utf8Encoded.arrayOffset(), utf8Encoded.remaining() );
}
else
{
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
index 2394ff0..16b97cf 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
import static org.apache.maven.surefire.util.internal.StringUtils.NL;
+import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
/**
* @author Kristian Rosenvold
@@ -125,7 +126,7 @@ public class WrappedReportEntry
public String getReportName( String suffix )
{
- return suffix != null && suffix.length() > 0 ? getReportName() + "(" + suffix + ")" : getReportName();
+ return isNotBlank( suffix ) ? getReportName() + "(" + suffix + ")" : getReportName();
}
public String getOutput( boolean trimStackTrace )
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
index a53db02..256e252 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
@@ -41,11 +41,11 @@ public class StatisticsReporter
this( dataFile, fromFile( dataFile ), new RunEntryStatisticsMap() );
}
- protected StatisticsReporter( File dataFile, RunEntryStatisticsMap existing, RunEntryStatisticsMap newRestuls )
+ protected StatisticsReporter( File dataFile, RunEntryStatisticsMap existing, RunEntryStatisticsMap newResults )
{
this.dataFile = dataFile;
this.existing = existing;
- this.newResults = newRestuls;
+ this.newResults = newResults;
}
public synchronized void testSetCompleted()
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/FileScanner.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/FileScanner.java
index 6636f29..8f4f0fd 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/FileScanner.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/FileScanner.java
@@ -62,7 +62,7 @@ final class FileScanner
for ( File fileOrDir : filesAndDirs )
{
String name = fileOrDir.getName();
- if ( name.length() != 0 )
+ if ( !name.isEmpty() )
{
if ( fileOrDir.isFile() )
{
@@ -74,7 +74,7 @@ final class FileScanner
if ( filter.shouldRun( toFile( path, simpleClassName ), null ) )
{
String fullyQualifiedClassName =
- pAckage.length() == 0 ? simpleClassName : pAckage + '.' + simpleClassName;
+ pAckage.isEmpty() ? simpleClassName : pAckage + '.' + simpleClassName;
scannedJavaClassNames.add( fullyQualifiedClassName );
}
}
@@ -122,7 +122,7 @@ final class FileScanner
private String toFile( String path, String fileNameWithoutExtension )
{
String pathWithoutExtension =
- path.length() == 0 ? fileNameWithoutExtension : path + '/' + fileNameWithoutExtension;
+ path.isEmpty() ? fileNameWithoutExtension : path + '/' + fileNameWithoutExtension;
return pathWithoutExtension + ext;
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
index 19356f5..461b6ce 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
@@ -25,6 +25,7 @@ import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.Notifiable
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.booter.ForkedChannelEncoder;
import org.apache.maven.surefire.booter.ForkingRunListener;
import org.apache.maven.surefire.report.CategorizedReportEntry;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
@@ -38,7 +39,6 @@ import org.apache.maven.surefire.report.StackTraceWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
-import java.nio.charset.Charset;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
@@ -57,10 +57,6 @@ public class ForkingRunListenerTest
private final PrintStream printStream, anotherPrintStream;
- final int defaultChannel = 17;
-
- final int anotherChannel = 18;
-
public ForkingRunListenerTest()
{
content = new ByteArrayOutputStream();
@@ -76,20 +72,6 @@ public class ForkingRunListenerTest
content.reset();
}
- public void testHeaderCreation()
- {
- final byte[] header = ForkingRunListener.createHeader( (byte) 'F', 0xCAFE );
- String asString = new String( header );
- assertEquals( "F,cafe," + Charset.defaultCharset().name() + ",", asString );
- }
-
- public void testHeaderCreationShort()
- {
- final byte[] header = ForkingRunListener.createHeader( (byte) 'F', 0xE );
- String asString = new String( header );
- assertEquals( "F,e," + Charset.defaultCharset().name() + ",", asString );
- }
-
public void testSetStarting()
throws ReporterException, IOException
{
@@ -207,7 +189,7 @@ public class ForkingRunListenerTest
{
final StandardTestRun standardTestRun = new StandardTestRun();
ConsoleOutputReceiver directConsoleReporter = (ConsoleOutputReceiver) standardTestRun.run();
- directConsoleReporter.writeTestOutput( "HeyYou".getBytes(), 0, 6, true );
+ directConsoleReporter.writeTestOutput( "HeyYou", true );
standardTestRun.assertExpected( MockReporter.STDOUT, "HeyYou" );
}
@@ -218,7 +200,7 @@ public class ForkingRunListenerTest
standardTestRun.run();
reset();
- createForkingRunListener( defaultChannel );
+ createForkingRunListener();
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
final Properties testVmSystemProperties = new Properties();
@@ -239,7 +221,7 @@ public class ForkingRunListenerTest
standardTestRun.run();
reset();
- RunListener forkingReporter = createForkingRunListener( defaultChannel );
+ RunListener forkingReporter = createForkingRunListener();
ReportEntry reportEntry = createDefaultReportEntry();
forkingReporter.testSetStarting( reportEntry );
@@ -269,10 +251,10 @@ public class ForkingRunListenerTest
ReportEntry expected = createDefaultReportEntry();
final SimpleReportEntry secondExpected = createAnotherDefaultReportEntry();
- new ForkingRunListener( printStream, defaultChannel, false )
+ new ForkingRunListener( new ForkedChannelEncoder( printStream ), false )
.testStarting( expected );
- new ForkingRunListener( anotherPrintStream, anotherChannel, false )
+ new ForkingRunListener( new ForkedChannelEncoder( anotherPrintStream ), false )
.testSkipped( secondExpected );
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
@@ -336,9 +318,9 @@ public class ForkingRunListenerTest
}
}
- private RunListener createForkingRunListener( Integer testSetChannel )
+ private RunListener createForkingRunListener()
{
- return new ForkingRunListener( printStream, testSetChannel, false );
+ return new ForkingRunListener( new ForkedChannelEncoder( printStream ), false );
}
private class StandardTestRun
@@ -349,7 +331,7 @@ public class ForkingRunListenerTest
throws ReporterException
{
reset();
- return createForkingRunListener( defaultChannel );
+ return createForkingRunListener();
}
public void clientReceiveContent()
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
index b8c9ef0..1b5e704 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
@@ -26,6 +26,7 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
/**
* Internal tests use only.
@@ -115,6 +116,11 @@ public class MockReporter
{
}
+ @Override
+ public RunMode markAs(RunMode currentRunMode) {
+ return null;
+ }
+
public void testSkippedByUser( ReportEntry report )
{
testSkipped( report );
@@ -179,9 +185,10 @@ public class MockReporter
{
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ @Override
+ public void writeTestOutput( String output, boolean stdout )
{
events.add( stdout ? STDOUT : STDERR );
- data.add( new String( buf, off, len ) );
+ data.add( output );
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
similarity index 60%
copy from surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
copy to maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
index 06d6414..3927ebc 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.report;
+package org.apache.maven.plugin.surefire.booterclient.output;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,20 @@ package org.apache.maven.surefire.report;
* under the License.
*/
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
- * A receiver of stdout/sterr output from running tests. This receiver knows how to associate
- * the output with a given testset.
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
*/
-public interface ConsoleOutputReceiver
+public class ForkClientTest
{
+ @Test
+ public void test()
+ {
+ ForkClient client = new ForkClient( null, null, null, null );
+ }
- /**
- * Forwards process output from the running test-case into the reporting system
- *
- * @param buf the buffer to write
- * @param off offset
- * @param len len
- * @param stdout Indicates if this is stdout
- */
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
-
-}
+}
\ No newline at end of file
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
new file mode 100644
index 0000000..1819b27
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
@@ -0,0 +1,717 @@
+package org.apache.maven.plugin.surefire.booterclient.output;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
+import org.apache.maven.surefire.booter.ForkedChannelEncoder;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Map;
+
+import static java.nio.charset.Charset.defaultCharset;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.maven.plugin.surefire.booterclient.output.ForkedChannelDecoder.toReportEntry;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.rules.ExpectedException.none;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+@RunWith( Enclosed.class )
+public class ForkedChannelDecoderTest
+{
+ public static class DecoderOperationsTest
+ {
+ @Rule
+ public final ExpectedException rule = none();
+
+ @Test
+ public void shouldBeFailSafe()
+ {
+ Charset encoding = Charset.defaultCharset();
+ assertThat( ForkedChannelDecoder.decode( null, encoding ) ).isNull();
+ assertThat( ForkedChannelDecoder.decode( "-", encoding ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToInteger( null ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToInteger( "-" ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToBytes( null ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToBytes( "-" ) ).isNull();
+ }
+
+ @Test
+ public void shouldHaveSystemProperty() throws IOException
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.sendSystemProperties();
+
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
+ LineNumberReader reader = out.newReader( defaultCharset() );
+ for ( String line; ( line = reader.readLine() ) != null; )
+ {
+ decoder.handleEvent( line, new AssertionErrorHandler() );
+ }
+ assertThat( reader.getLineNumber() ).isPositive();
+ }
+
+ @Test
+ public void shouldRecognizeEmptyStream4ReportEntry()
+ {
+ ReportEntry reportEntry = toReportEntry( null, null, "", null, null, "", "", "", null );
+ assertThat( reportEntry ).isNull();
+
+ reportEntry = toReportEntry( defaultCharset(), "", "", "", "", "-", "", "", "" );
+ assertThat( reportEntry ).isNotNull();
+ assertThat( reportEntry.getStackTraceWriter() ).isNull();
+ assertThat( reportEntry.getSourceName() ).isEmpty();
+ assertThat( reportEntry.getName() ).isEmpty();
+ assertThat( reportEntry.getGroup() ).isEmpty();
+ assertThat( reportEntry.getNameWithGroup() ).isEmpty();
+ assertThat( reportEntry.getMessage() ).isEmpty();
+ assertThat( reportEntry.getElapsed() ).isNull();
+
+ rule.expect( NumberFormatException.class );
+ toReportEntry( defaultCharset(), "", "", "", "", "", "", "", "" );
+ fail();
+ }
+
+ @Test
+ public void testCreatingReportEntry()
+ {
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ final String exceptionMessage = "msg";
+ final String encodedExceptionMsg = printBase64Binary( toArray( utf8.encode( exceptionMessage ) ) );
+
+ final String smartStackTrace = "MyTest:86 >> Error";
+ final String encodedSmartStackTrace = printBase64Binary( toArray( utf8.encode( smartStackTrace ) ) );
+
+ final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
+ final String encodedStackTrace = printBase64Binary( toArray( utf8.encode( stackTrace ) ) );
+
+ final String trimmedStackTrace = "trace line 1\ntrace line 2";
+ final String encodedTrimmedStackTrace = printBase64Binary( toArray( utf8.encode( trimmedStackTrace ) ) );
+
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( 102 );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( "skipped test" );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ String encodedSourceName = printBase64Binary( toArray( utf8.encode( reportEntry.getSourceName() ) ) );
+ String encodedName = printBase64Binary( toArray( utf8.encode( reportEntry.getName() ) ) );
+ String encodedGroup = printBase64Binary( toArray( utf8.encode( reportEntry.getGroup() ) ) );
+ String encodedMessage = printBase64Binary( toArray( utf8.encode( reportEntry.getMessage() ) ) );
+
+ ReportEntry decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup,
+ encodedMessage, "-", null, null, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage, "-",
+ encodedExceptionMsg, encodedSmartStackTrace, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isNull();
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace,
+ encodedStackTrace
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace,
+ encodedTrimmedStackTrace
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( trimmedStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() )
+ .isEqualTo( trimmedStackTrace );
+ }
+
+ @Test
+ public void shouldSendByeEvent() throws IOException
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.bye();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:bye\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setByeListener( new EventAssertionListener() );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldSendStopOnNextTestEvent() throws IOException
+ {
+
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.stopOnNextTest();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:stop-on-next-test\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStopOnNextTestListener( new EventAssertionListener() );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldSendNextTestEvent() throws IOException
+ {
+
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.acquireNextTest();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:next-test\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setAcquireNextTestListener( new EventAssertionListener() );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testConsole() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.console( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleInfoListener( new StringEventAssertionListener( "msg" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testError() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.error( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleErrorListener( new StackTraceEventListener( "msg", null, null ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions( errorHandler );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testErrorWithException() throws IOException
+ {
+ Throwable t = new Throwable( "msg" );
+
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.error( t );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ String stackTrace = ConsoleLoggerUtils.toString( t );
+ decoder.setConsoleErrorListener( new StackTraceEventListener( "msg", null, stackTrace ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions( errorHandler );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testErrorWithStackTraceWriter() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "1", "2", "3" );
+ forkedChannelEncoder.error( stackTraceWriter, false );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleErrorListener( new StackTraceEventListener( "1", "2", "3" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions( errorHandler );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testDebug() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.debug( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleDebugListener( new StringEventAssertionListener( "msg" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testWarning() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.warning( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleWarningListener( new StringEventAssertionListener( "msg" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testStdOutStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "UTF-8" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdOut( msgArray, 0, msgArray.length );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStdOutListener( new BinaryEventAssertionListener( NORMAL_RUN, "msg" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testStdErrStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdErr( msgArray, 0, msgArray.length );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStdErrListener( new BinaryEventAssertionListener( NORMAL_RUN, "msg" ) );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldCountSameNumberOfSystemProperties() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+ forkedChannelEncoder.sendSystemProperties();
+
+ LineNumberReader lines = out.newReader( streamEncoding );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setSystemPropertiesListener( new PropertyEventAssertionListener() );
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( lines.readLine(), errorHandler );
+ verifyZeroInteractions(errorHandler);
+ }
+ }
+
+ @RunWith( Theories.class )
+ public static class ReportEntryTest
+ {
+ @DataPoints( value = "operation" )
+ public static String[][] operations = { { "testSetStarting", "setTestSetStartingListener" },
+ { "testSetCompleted", "setTestSetCompletedListener" },
+ { "testStarting", "setTestStartingListener" },
+ { "testSucceeded", "setTestSucceededListener" },
+ { "testFailed", "setTestFailedListener" },
+ { "testSkipped", "setTestSkippedListener" },
+ { "testError", "setTestErrorListener" },
+ { "testAssumptionFailure", "setTestAssumptionFailureListener" }
+ };
+
+ @DataPoints( value = "reportedMessage" )
+ public static String[] reportedMessage = { null, "skipped test" };
+
+ @DataPoints( value = "elapsed" )
+ public static Integer[] elapsed = { null, 102 };
+
+ @DataPoints( value = "trim" )
+ public static boolean[] trim = { false, true };
+
+ @DataPoints( value = "msg" )
+ public static boolean[] msg = { false, true };
+
+ @DataPoints( value = "smart" )
+ public static boolean[] smart = { false, true };
+
+ @DataPoints( value = "trace" )
+ public static boolean[] trace = { false, true };
+
+ @Theory
+ public void testReportEntryOperations( @FromDataPoints( "operation" ) String[] operation,
+ @FromDataPoints( "reportedMessage" ) String reportedMessage,
+ @FromDataPoints( "elapsed" ) Integer elapsed,
+ @FromDataPoints( "trim" ) boolean trim,
+ @FromDataPoints( "msg" ) boolean msg,
+ @FromDataPoints( "smart" ) boolean smart,
+ @FromDataPoints( "trace" ) boolean trace )
+ throws Exception
+ {
+ String exceptionMessage = msg ? "msg" : null;
+ String smartStackTrace = smart ? "MyTest:86 >> Error" : null;
+ String exceptionStackTrace =
+ trace ? ( trim ? "trace line 1\ntrace line 2" : "Exception: msg\ntrace line 1\ntrace line 2" )
+ : null;
+
+ StackTraceWriter stackTraceWriter = null;
+ if ( exceptionStackTrace != null )
+ {
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
+ }
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( elapsed );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( reportedMessage );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ ForkedChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
+ .invoke( forkedChannelEncoder, reportEntry, trim );
+
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+
+ ForkedChannelDecoder.class.getMethod( operation[1], ForkedProcessReportEventListener.class )
+ .invoke( decoder, new ReportEventAssertionListener( reportEntry ) );
+
+ AssertionErrorHandler errorHandler = mock( AssertionErrorHandler.class );
+ decoder.handleEvent( out.newReader( defaultCharset() ).readLine(), errorHandler );
+ verifyZeroInteractions( errorHandler );
+ }
+ }
+
+ private static class AssertionErrorHandler implements ForkedChannelDecoderErrorHandler
+ {
+ public void handledError( String line, Throwable e )
+ {
+ if ( e != null )
+ {
+ e.printStackTrace();
+ }
+ fail( line + ( e == null ? "" : "\n" + e.getLocalizedMessage() ) );
+ }
+ }
+
+ private static class PropertyEventAssertionListener implements ForkedProcessPropertyEventListener
+ {
+ private final Map sysProps = System.getProperties();
+
+ public void handle( RunMode runMode, String key, String value )
+ {
+ assertThat( runMode ).isEqualTo( NORMAL_RUN );
+ assertTrue( sysProps.containsKey( key ) );
+ assertThat( sysProps.get( key ) ).isEqualTo( value );
+ }
+ }
+
+ private static class EventAssertionListener implements ForkedProcessEventListener
+ {
+ public void handle()
+ {
+ }
+ }
+
+ private static class StringEventAssertionListener implements ForkedProcessStringEventListener
+ {
+ private final String msg;
+
+ StringEventAssertionListener( String msg )
+ {
+ this.msg = msg;
+ }
+
+ public void handle( String msg )
+ {
+ assertThat( msg )
+ .isEqualTo( this.msg );
+ }
+ }
+
+ private static class StackTraceEventListener implements ForkedProcessStackTraceEventListener
+ {
+ private final String msg;
+ private final String smartStackTrace;
+ private final String stackTrace;
+
+ StackTraceEventListener( String msg, String smartStackTrace, String stackTrace )
+ {
+ this.msg = msg;
+ this.smartStackTrace = smartStackTrace;
+ this.stackTrace = stackTrace;
+ }
+
+ @Override
+ public void handle( String msg, String smartStackTrace, String stackTrace )
+ {
+ assertThat( msg )
+ .isEqualTo( this.msg );
+
+ assertThat( smartStackTrace )
+ .isEqualTo( this.smartStackTrace );
+
+ assertThat( stackTrace )
+ .isEqualTo( this.stackTrace );
+ }
+ }
+
+ private static class BinaryEventAssertionListener implements ForkedProcessBinaryEventListener
+ {
+ private final RunMode runMode;
+ private final String output;
+
+ BinaryEventAssertionListener( RunMode runMode, String output )
+ {
+ this.runMode = runMode;
+ this.output = output;
+ }
+
+ public void handle( RunMode runMode, String output )
+ {
+ assertThat( runMode )
+ .isEqualTo( this.runMode );
+
+ assertThat( output )
+ .isEqualTo( this.output );
+ }
+ }
+
+ private static class ReportEventAssertionListener implements ForkedProcessReportEventListener
+ {
+ private final ReportEntry reportEntry;
+
+ ReportEventAssertionListener( ReportEntry reportEntry )
+ {
+ this.reportEntry = reportEntry;
+ }
+
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
+ assertThat( reportEntry.getName() ).isEqualTo( this.reportEntry.getName() );
+ assertThat( reportEntry.getGroup() ).isEqualTo( this.reportEntry.getGroup() );
+ assertThat( reportEntry.getMessage() ).isEqualTo( this.reportEntry.getMessage() );
+ assertThat( reportEntry.getElapsed() ).isEqualTo( this.reportEntry.getElapsed() );
+ if ( reportEntry.getStackTraceWriter() == null )
+ {
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNull();
+ }
+ else
+ {
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNotNull();
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().smartTrimmedStackTrace() );
+ }
+ }
+ }
+
+ private static class Stream extends PrintStream
+ {
+ private final ByteArrayOutputStream out;
+
+ public Stream( ByteArrayOutputStream out )
+ {
+ super( out, true );
+ this.out = out;
+ }
+
+ byte[] toByteArray()
+ {
+ return out.toByteArray();
+ }
+
+ LineNumberReader newReader( Charset streamCharset )
+ {
+ return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
+ }
+
+ static Stream newStream()
+ {
+ return new Stream( new ByteArrayOutputStream() );
+ }
+ }
+
+ private static byte[] toArray( ByteBuffer buffer )
+ {
+ return Arrays.copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index 9fb45bf..0c92635 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -30,6 +30,7 @@ import org.apache.maven.plugin.surefire.booterclient.ForkConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.ForkingRunListenerTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactoryTest;
import org.apache.maven.plugin.surefire.report.StatelessXmlReporterTest;
import org.apache.maven.plugin.surefire.report.WrappedReportEntryTest;
@@ -75,6 +76,7 @@ import org.junit.runners.Suite;
SurefireReflectorTest.class,
ImmutableMapTest.class,
SurefireHelperTest.class,
+ ForkClientTest.class
} )
@RunWith( Suite.class )
public class JUnit4SuiteTest
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
index 6943b70..54d4667 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
@@ -43,7 +43,7 @@ public class ConsoleOutputFileReporterTest
reportEntry = new SimpleReportEntry( this.getClass().getName(), testName );
reporter = new ConsoleOutputFileReporter( reportDir, null );
reporter.testSetStarting( reportEntry );
- reporter.writeTestOutput( "some text".getBytes(), 0, 5, true );
+ reporter.writeTestOutput( "some ", true );
reporter.testSetCompleted( reportEntry );
File expectedReportFile = new File( reportDir, testName + "-output.txt" );
@@ -62,7 +62,7 @@ public class ConsoleOutputFileReporterTest
reportEntry = new SimpleReportEntry( this.getClass().getName(), testName );
reporter = new ConsoleOutputFileReporter( reportDir, suffixText );
reporter.testSetStarting( reportEntry );
- reporter.writeTestOutput( "some text".getBytes(), 0, 5, true );
+ reporter.writeTestOutput( "some ", true );
reporter.testSetCompleted( reportEntry );
File expectedReportFile = new File( reportDir, testName + "-" + suffixText + "-output.txt" );
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index 5f0f2fd..b705e0a 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -40,6 +40,11 @@
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
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 2a713ef..10cd7a7 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
@@ -36,7 +36,6 @@ import org.apache.maven.surefire.util.DirectoryScanner;
import org.apache.maven.surefire.util.RunOrderCalculator;
import org.apache.maven.surefire.util.ScanResult;
-import java.io.PrintStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -51,12 +50,12 @@ public class BaseProviderFactory
ProviderPropertiesAware, ProviderParameters, TestArtifactInfoAware, RunOrderParametersAware, MainCliOptionsAware,
FailFastAware, ShutdownAware
{
- private static final int ROOT_CHANNEL = 0;
-
private final ReporterFactory reporterFactory;
private final boolean insideFork;
+ private ForkedChannelEncoder forkedChannelEncoder;
+
private List<CommandLineOption> mainCliOptions = emptyList();
private Map<String, String> providerProperties;
@@ -134,9 +133,8 @@ public class BaseProviderFactory
public ConsoleStream getConsoleLogger()
{
- boolean trim = reporterConfiguration.isTrimStackTrace();
- PrintStream out = reporterConfiguration.getOriginalSystemOut();
- return insideFork ? new ForkingRunListener( out, ROOT_CHANNEL, trim ) : new DefaultDirectConsoleReporter( out );
+ return insideFork ? new ForkingRunListener( forkedChannelEncoder, reporterConfiguration.isTrimStackTrace() )
+ : new DefaultDirectConsoleReporter( reporterConfiguration.getOriginalSystemOut() );
}
public void setTestRequest( TestRequest testRequest )
@@ -233,4 +231,14 @@ public class BaseProviderFactory
{
this.systemExitTimeout = systemExitTimeout;
}
+
+ public ForkedChannelEncoder getForkedChannelEncoder()
+ {
+ return forkedChannelEncoder;
+ }
+
+ public void setForkedChannelEncoder( ForkedChannelEncoder forkedChannelEncoder )
+ {
+ this.forkedChannelEncoder = forkedChannelEncoder;
+ }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index 2e80f44..3702270 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -26,7 +26,6 @@ import org.apache.maven.surefire.testset.TestSetFailedException;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
-import java.io.PrintStream;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
@@ -41,7 +40,6 @@ import static java.lang.Thread.State.RUNNABLE;
import static java.lang.Thread.State.TERMINATED;
import static java.lang.StrictMath.max;
import static org.apache.maven.surefire.booter.Command.toShutdown;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_NEXT_TEST;
import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
@@ -50,7 +48,6 @@ import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_N
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.encodeStringForForkCommunication;
import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
@@ -190,7 +187,7 @@ public final class CommandReader
}
/**
- * @return test classes which have been retrieved by {@link CommandReader#getIterableClasses(PrintStream)}.
+ * @return test classes which have been retrieved by {@link CommandReader#getIterableClasses(ForkedChannelEncoder)}.
*/
Iterator<String> iterated()
{
@@ -201,12 +198,12 @@ public final class CommandReader
* The iterator can be used only in one Thread.
* Two simultaneous instances are not allowed for sake of only one {@link #nextCommandNotifier}.
*
- * @param originalOutStream original stream in current JVM process
+ * @param eventChannel original stream in current JVM process
* @return Iterator with test classes lazily loaded as commands from the main process
*/
- Iterable<String> getIterableClasses( PrintStream originalOutStream )
+ Iterable<String> getIterableClasses( ForkedChannelEncoder eventChannel )
{
- return new ClassesIterable( originalOutStream );
+ return new ClassesIterable( eventChannel );
}
public void stop()
@@ -254,31 +251,31 @@ public final class CommandReader
private final class ClassesIterable
implements Iterable<String>
{
- private final PrintStream originalOutStream;
+ private final ForkedChannelEncoder eventChannel;
- ClassesIterable( PrintStream originalOutStream )
+ ClassesIterable( ForkedChannelEncoder eventChannel )
{
- this.originalOutStream = originalOutStream;
+ this.eventChannel = eventChannel;
}
public Iterator<String> iterator()
{
- return new ClassesIterator( originalOutStream );
+ return new ClassesIterator( eventChannel );
}
}
private final class ClassesIterator
implements Iterator<String>
{
- private final PrintStream originalOutStream;
+ private final ForkedChannelEncoder eventChannel;
private String clazz;
private int nextQueueIndex;
- private ClassesIterator( PrintStream originalOutStream )
+ private ClassesIterator( ForkedChannelEncoder eventChannel )
{
- this.originalOutStream = originalOutStream;
+ this.eventChannel = eventChannel;
}
public boolean hasNext()
@@ -341,12 +338,7 @@ public final class CommandReader
private void requestNextTest()
{
- byte[] encoded = encodeStringForForkCommunication( ( (char) BOOTERCODE_NEXT_TEST ) + ",0,want more!\n" );
- synchronized ( originalOutStream )
- {
- originalOutStream.write( encoded, 0, encoded.length );
- originalOutStream.flush();
- }
+ eventChannel.acquireNextTest();
}
private boolean shouldFinish()
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java
new file mode 100644
index 0000000..d8ac89a
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java
@@ -0,0 +1,461 @@
+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.plugin.surefire.log.api.ConsoleLoggerUtils;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import static java.lang.System.arraycopy;
+import static java.nio.charset.Charset.defaultCharset;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SUCCEEDED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.MAGIC_NUMBER;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.report.RunMode.RERUN;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
+
+/**
+ * magic number : opcode : run mode [: opcode specific data]*
+ * <p/>
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public final class ForkedChannelEncoder
+{
+ private final Charset streamCharset;
+ private final OutputStream out;
+ private final RunMode runMode;
+ private volatile boolean trouble;
+
+ public ForkedChannelEncoder( OutputStream out )
+ {
+ this( US_ASCII, out, NORMAL_RUN );
+ }
+
+ /**
+ * For testing purposes.
+ *
+ * @param streamCharset pipe encoding
+ * @param out pipe
+ */
+ public ForkedChannelEncoder( Charset streamCharset, OutputStream out )
+ {
+ this( streamCharset, out, NORMAL_RUN );
+ }
+
+ private ForkedChannelEncoder( Charset streamCharset, OutputStream out, RunMode runMode )
+ {
+ this.streamCharset = requireNonNull( streamCharset );
+ this.out = requireNonNull( out );
+ this.runMode = requireNonNull( runMode );
+ }
+
+ public ForkedChannelEncoder asRerunMode() // todo apply this and rework providers
+ {
+ return new ForkedChannelEncoder( streamCharset, out, RERUN );
+ }
+
+ public ForkedChannelEncoder asNormalMode()
+ {
+ return new ForkedChannelEncoder( streamCharset, out, NORMAL_RUN );
+ }
+
+ public boolean checkError()
+ {
+ return trouble;
+ }
+
+ public void sendSystemProperties()
+ {
+ SortedMap<String, String> sortedProperties = new TreeMap<String, String>();
+ for ( Entry<?, ?> entry : System.getProperties().entrySet() )
+ {
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ if ( key instanceof String && ( value == null || value instanceof String ) )
+ {
+ sortedProperties.put( (String) key, (String) value );
+ }
+ }
+
+ for ( Entry<String, String> entry : sortedProperties.entrySet() )
+ {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ String valueAsString = value == null ? null : value.toString();
+ StringBuilder event = encode( BOOTERCODE_SYSPROPS, runMode, key, valueAsString );
+ encodeAndPrintEvent( event );
+ }
+ }
+
+ public void testSetStarting( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSetCompleted( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testStarting( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_STARTING, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSucceeded( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testFailed( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_FAILED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSkipped( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testError( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_ERROR, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testAssumptionFailure( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void stdOut( byte[] buf, int off, int len )
+ {
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDOUT.getOpcode(), runMode.geRunName(), buf, off, len, defaultCharset() );
+ encodeAndPrintEvent( event );
+ }
+
+ public void stdOut( String msg )
+ {
+ byte[] buf = ( msg == null ? "null" : msg ).getBytes( UTF_8 );
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDOUT.getOpcode(), runMode.geRunName(), buf, 0, buf.length, UTF_8 );
+ encodeAndPrintEvent( event );
+ }
+
+ public void stdErr( byte[] buf, int off, int len )
+ {
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDERR.getOpcode(), runMode.geRunName(), buf, off, len, defaultCharset() );
+ encodeAndPrintEvent( event );
+ }
+
+ public void stdErr( String msg )
+ {
+ byte[] buf = ( msg == null ? "null" : msg ).getBytes( UTF_8 );
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDERR.getOpcode(), runMode.geRunName(), buf, 0, buf.length, UTF_8 );
+ encodeAndPrintEvent( event );
+ }
+
+ public void console( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_INFO.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void error( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_ERROR.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void error( Throwable t )
+ {
+ error( t.getLocalizedMessage(), t );
+ }
+
+ public void error( String msg, Throwable t )
+ {
+ StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), runMode.geRunName(), UTF_8 );
+ encode( encoded, msg, null, ConsoleLoggerUtils.toString( t ) );
+ encodeAndPrintEvent( encoded );
+ }
+
+ public void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces )
+ {
+ StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), runMode.geRunName(), UTF_8 );
+ encode( encoded, stackTraceWriter, trimStackTraces );
+ encodeAndPrintEvent( encoded );
+ }
+
+ public void debug( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_DEBUG.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void warning( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_WARNING.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void bye()
+ {
+ encodeOpcode( BOOTERCODE_BYE );
+ }
+
+ public void stopOnNextTest()
+ {
+ encodeOpcode( BOOTERCODE_STOP_ON_NEXT_TEST );
+ }
+
+ public void acquireNextTest()
+ {
+ encodeOpcode( BOOTERCODE_NEXT_TEST );
+ }
+
+ private void encode( ForkedProcessEvent operation, RunMode runMode, ReportEntry reportEntry,
+ boolean trimStackTraces )
+ {
+ StringBuilder event = encode( operation.getOpcode(), runMode.geRunName(), reportEntry, trimStackTraces );
+ encodeAndPrintEvent( event );
+ }
+
+ private void encodeOpcode( ForkedProcessEvent operation )
+ {
+ StringBuilder event = encodeOpcode( runMode.geRunName(), operation.getOpcode() );
+ encodeAndPrintEvent( event );
+ }
+
+ private void encodeAndPrintEvent( StringBuilder command )
+ {
+ byte[] array = command.append( '\n' ).toString().getBytes( streamCharset );
+ synchronized ( out )
+ {
+ try
+ {
+ out.write( array );
+ out.flush();
+ }
+ catch ( IOException e )
+ {
+ DumpErrorSingleton.getSingleton().dumpException( e );
+ trouble = true;
+ }
+ }
+ }
+
+ static StringBuilder encode( ForkedProcessEvent operation, RunMode runMode, String... args )
+ {
+ StringBuilder encodedTo = encodeHeader( operation.getOpcode(), runMode.geRunName(), UTF_8 )
+ .append( ':' );
+
+ for ( int i = 0; i < args.length; )
+ {
+ String arg = args[i++];
+ base64WithUtf8( encodedTo, arg == null ? "-" : arg );
+ if ( i != args.length )
+ {
+ encodedTo.append( ':' );
+ }
+ }
+ return encodedTo;
+ }
+
+ static void encode( StringBuilder encoded, StackTraceWriter stw, boolean trimStackTraces )
+ {
+ SafeThrowable throwable = stw == null ? null : stw.getThrowable();
+ String message = throwable == null ? null : throwable.getLocalizedMessage();
+ String smartStackTrace = stw == null ? null : stw.smartTrimmedStackTrace();
+ String stackTrace = stw == null ? null : toStackTrace( stw, trimStackTraces );
+ encode( encoded, message, smartStackTrace, stackTrace );
+ }
+
+ private static void encode( StringBuilder encoded, String message, String smartStackTrace, String stackTrace )
+ {
+ encoded.append( ':' );
+ base64WithUtf8( encoded, message );
+ encoded.append( ':' );
+ base64WithUtf8( encoded, smartStackTrace );
+ encoded.append( ':' );
+ base64WithUtf8( encoded, stackTrace );
+ }
+
+ /**
+ * Used operations:<br/>
+ * <p>
+ * <ul>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TESTSET_STARTING},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TESTSET_COMPLETED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_STARTING},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_SUCCEEDED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_FAILED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_ERROR},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_SKIPPED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_ASSUMPTIONFAILURE}.</li>
+ * </ul>
+ * </p>
+ */
+ static StringBuilder encode( String operation, String runMode, ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ StringBuilder encodedTo = encodeHeader( operation, runMode, UTF_8 )
+ .append( ':' );
+
+ base64WithUtf8( encodedTo, reportEntry.getSourceName() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getName() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getGroup() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getMessage() );
+ encodedTo.append( ':' )
+ .append( reportEntry.getElapsed() == null ? "-" : reportEntry.getElapsed().toString() );
+ encode( encodedTo, reportEntry.getStackTraceWriter(), trimStackTraces );
+
+ return encodedTo;
+ }
+
+ static StringBuilder stdOutErr( String operation, String runMode, byte[] buf, int off, int len,
+ Charset bufEncoding )
+ {
+ final byte[] encodeBytes;
+ if ( off == 0 && buf.length == len )
+ {
+ encodeBytes = buf;
+ }
+ else
+ {
+ encodeBytes = new byte[len];
+ arraycopy( buf, off, encodeBytes, 0, len );
+ }
+ return encodeMessage( operation, runMode, bufEncoding, printBase64Binary( encodeBytes ) );
+ }
+
+ /**
+ * Used in {@link #console(String)}, {@link #error(String)}, {@link #debug(String)} and {@link #warning(String)}
+ * and private methods extending the buffer.
+ */
+ static StringBuilder print( String operation, String runMode, Charset msgEncoding, String... msgs )
+ {
+ String[] encodedMsgs = new String[msgs.length];
+ for ( int i = 0; i < encodedMsgs.length; i++ )
+ {
+ String msg = msgs[i];
+ encodedMsgs[i] = msg == null ? "-" : toBase64( msg, msgEncoding );
+ }
+ return encodeMessage( operation, runMode, msgEncoding, encodedMsgs );
+ }
+
+ static StringBuilder encodeMessage( String operation, String runMode, Charset encoding, String... msgs )
+ {
+ StringBuilder builder = encodeHeader( operation, runMode, encoding );
+ for ( String msg : msgs )
+ {
+ builder.append( ':' )
+ .append( msg );
+
+ }
+ return builder;
+ }
+
+ static StringBuilder encodeHeader( String operation, String runMode, Charset encoding )
+ {
+ return encodeOpcode( runMode, operation )
+ .append( ':' )
+ .append( encoding.name() );
+ }
+
+ /**
+ * Used in {@link #bye()}, {@link #stopOnNextTest()} and {@link #encodeOpcode(ForkedProcessEvent)}
+ * and private methods extending the buffer.
+ *
+ * @param runMode run mode
+ * @param operation opcode
+ * @return encoded command
+ */
+ static StringBuilder encodeOpcode( String runMode, String operation )
+ {
+ return new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( runMode )
+ .append( ':' )
+ .append( operation );
+ }
+
+ static String base64WithUtf8( String msg )
+ {
+ if ( msg == null )
+ {
+ return "-";
+ }
+ else
+ {
+ byte[] binary = msg.getBytes( UTF_8 );
+ return printBase64Binary( binary );
+ }
+ }
+
+ static void base64WithUtf8( StringBuilder encoded, String msg )
+ {
+ encoded.append( base64WithUtf8( msg ) );
+ }
+
+ private static String toStackTrace( StackTraceWriter stw, boolean trimStackTraces )
+ {
+ return trimStackTraces ? stw.writeTrimmedTraceToString() : stw.writeTraceToString();
+ }
+
+ static String toBase64( String msg, Charset encoding )
+ {
+ return msg == null ? "-" : printBase64Binary( msg.getBytes( encoding ) );
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
new file mode 100644
index 0000000..a75d5ba
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
@@ -0,0 +1,129 @@
+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 java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * Events sent back to the plugin process.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public enum ForkedProcessEvent
+{
+ BOOTERCODE_SYSPROPS( "sys-prop" ),
+
+ BOOTERCODE_TESTSET_STARTING( "testset-starting" ),
+ BOOTERCODE_TESTSET_COMPLETED( "testset-completed" ),
+ BOOTERCODE_TEST_STARTING( "test-starting" ),
+ BOOTERCODE_TEST_SUCCEEDED( "test-succeeded" ),
+ BOOTERCODE_TEST_FAILED( "test-failed" ),
+ BOOTERCODE_TEST_SKIPPED( "test-skipped" ),
+ BOOTERCODE_TEST_ERROR( "test-error" ),
+ BOOTERCODE_TEST_ASSUMPTIONFAILURE( "test-assumption-failure" ),
+
+ BOOTERCODE_STDOUT( "std-out-stream" ),
+ BOOTERCODE_STDERR( "std-err-stream" ),
+
+ BOOTERCODE_CONSOLE_INFO( "console" ),
+ BOOTERCODE_CONSOLE_DEBUG( "debug" ),
+ BOOTERCODE_CONSOLE_WARNING( "warning" ),
+ BOOTERCODE_CONSOLE_ERROR( "error" ),
+
+ BOOTERCODE_BYE( "bye" ),
+ BOOTERCODE_STOP_ON_NEXT_TEST( "stop-on-next-test" ),
+ BOOTERCODE_NEXT_TEST( "next-test" ),
+
+ BOOTERCODE_JVM_EXIT_ERROR( "jvm-exit-error" );
+
+ public static final String MAGIC_NUMBER = ":maven:surefire:std:out:";
+
+ public static final Map<String, ForkedProcessEvent> EVENTS = events();
+
+ private static Map<String, ForkedProcessEvent> events()
+ {
+ Map<String, ForkedProcessEvent> events = new ConcurrentHashMap<String, ForkedProcessEvent>();
+ for ( ForkedProcessEvent event : values() )
+ {
+ events.put( event.getOpcode(), event );
+ }
+ return unmodifiableMap( events );
+ }
+
+ private final String opcode;
+
+ ForkedProcessEvent( String opcode )
+ {
+ this.opcode = opcode;
+ }
+
+ public String getOpcode()
+ {
+ return opcode;
+ }
+
+ public boolean isSysPropCategory()
+ {
+ return this == BOOTERCODE_SYSPROPS;
+ }
+
+ public boolean isTestCategory()
+ {
+ return this == BOOTERCODE_TESTSET_STARTING
+ || this == BOOTERCODE_TESTSET_COMPLETED
+ || this == BOOTERCODE_TEST_STARTING
+ || this == BOOTERCODE_TEST_SUCCEEDED
+ || this == BOOTERCODE_TEST_FAILED
+ || this == BOOTERCODE_TEST_SKIPPED
+ || this == BOOTERCODE_TEST_ERROR
+ || this == BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+ }
+
+ public boolean isStandardStreamCategory()
+ {
+ return this == BOOTERCODE_STDOUT || this == BOOTERCODE_STDERR;
+ }
+
+ public boolean isConsoleCategory()
+ {
+ return this == BOOTERCODE_CONSOLE_INFO
+ || this == BOOTERCODE_CONSOLE_DEBUG
+ || this == BOOTERCODE_CONSOLE_WARNING;
+ }
+
+ public boolean isConsoleErrorCategory()
+ {
+ return this == BOOTERCODE_CONSOLE_ERROR;
+ }
+
+ public boolean isControlCategory()
+ {
+ return this == BOOTERCODE_BYE || this == BOOTERCODE_STOP_ON_NEXT_TEST || this == BOOTERCODE_NEXT_TEST;
+ }
+
+ public boolean isJvmExitError()
+ {
+ return this == BOOTERCODE_JVM_EXIT_ERROR;
+ }
+}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
index def345d..b3a7213 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
@@ -19,9 +19,6 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.PrintStream;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.suite.RunResult;
@@ -37,21 +34,19 @@ import org.apache.maven.surefire.suite.RunResult;
public class ForkingReporterFactory
implements ReporterFactory
{
- private final boolean isTrimstackTrace;
-
- private final PrintStream originalSystemOut;
+ private final boolean trimstackTrace;
- private final AtomicInteger testSetChannelId = new AtomicInteger( 1 );
+ private final ForkedChannelEncoder eventChannel;
- public ForkingReporterFactory( boolean trimstackTrace, PrintStream originalSystemOut )
+ public ForkingReporterFactory( boolean trimstackTrace, ForkedChannelEncoder eventChannel )
{
- isTrimstackTrace = trimstackTrace;
- this.originalSystemOut = originalSystemOut;
+ this.trimstackTrace = trimstackTrace;
+ this.eventChannel = eventChannel;
}
public RunListener createReporter()
{
- return new ForkingRunListener( originalSystemOut, testSetChannelId.getAndIncrement(), isTrimstackTrace );
+ return new ForkingRunListener( eventChannel, trimstackTrace );
}
public RunResult close()
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index 6c0842a..973e5a2 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -19,24 +19,15 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.PrintStream;
-import java.util.Properties;
-
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
-import org.apache.maven.surefire.report.SafeThrowable;
-import org.apache.maven.surefire.report.SimpleReportEntry;
-import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.RunMode;
-import static java.lang.Integer.toHexString;
-import static java.nio.charset.Charset.defaultCharset;
-import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
-import static org.apache.maven.surefire.util.internal.StringUtils.escapeBytesToPrintable;
-import static org.apache.maven.surefire.util.internal.StringUtils.escapeToPrintable;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
/**
* Encodes the full output of the test run to the stdout stream.
@@ -51,216 +42,118 @@ import static org.apache.maven.surefire.util.internal.StringUtils.escapeToPrinta
* The synchronization in the underlying PrintStream (target instance)
* is used to preserve thread safety of the output stream. To perform
* multiple writes/prints for a single request, they must
- * synchronize on "target" variable in this class.
+ * synchronize on "target.out" variable in this class.
*
* @author Kristian Rosenvold
*/
public class ForkingRunListener
implements RunListener, ConsoleLogger, ConsoleOutputReceiver, ConsoleStream
{
- public static final byte BOOTERCODE_TESTSET_STARTING = (byte) '1';
-
- public static final byte BOOTERCODE_TESTSET_COMPLETED = (byte) '2';
-
- public static final byte BOOTERCODE_STDOUT = (byte) '3';
-
- public static final byte BOOTERCODE_STDERR = (byte) '4';
-
- public static final byte BOOTERCODE_TEST_STARTING = (byte) '5';
-
- public static final byte BOOTERCODE_TEST_SUCCEEDED = (byte) '6';
-
- public static final byte BOOTERCODE_TEST_ERROR = (byte) '7';
-
- public static final byte BOOTERCODE_TEST_FAILED = (byte) '8';
-
- public static final byte BOOTERCODE_TEST_SKIPPED = (byte) '9';
-
- public static final byte BOOTERCODE_TEST_ASSUMPTIONFAILURE = (byte) 'G';
-
- /**
- * INFO logger
- * @see ConsoleLogger#info(String)
- */
- public static final byte BOOTERCODE_CONSOLE = (byte) 'H';
-
- public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';
+ private final ForkedChannelEncoder target;
- public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';
+ private final boolean trim;
- public static final byte BOOTERCODE_STOP_ON_NEXT_TEST = (byte) 'S';
+ private volatile RunMode runMode = NORMAL_RUN;
- /**
- * ERROR logger
- * @see ConsoleLogger#error(String)
- */
- public static final byte BOOTERCODE_ERROR = (byte) 'X';
-
- public static final byte BOOTERCODE_BYE = (byte) 'Z';
-
- /**
- * DEBUG logger
- * @see ConsoleLogger#debug(String)
- */
- public static final byte BOOTERCODE_DEBUG = (byte) 'D';
-
- /**
- * WARNING logger
- * @see ConsoleLogger#warning(String)
- */
- public static final byte BOOTERCODE_WARNING = (byte) 'W';
-
-
- private final PrintStream target;
-
- private final int testSetChannelId;
-
- private final boolean trimStackTraces;
-
- private final byte[] stdOutHeader;
-
- private final byte[] stdErrHeader;
-
- public ForkingRunListener( PrintStream target, int testSetChannelId, boolean trimStackTraces )
+ public ForkingRunListener( ForkedChannelEncoder target, boolean trim )
{
this.target = target;
- this.testSetChannelId = testSetChannelId;
- this.trimStackTraces = trimStackTraces;
- stdOutHeader = createHeader( BOOTERCODE_STDOUT, testSetChannelId );
- stdErrHeader = createHeader( BOOTERCODE_STDERR, testSetChannelId );
- sendProps();
+ this.trim = trim;
+ sendProps(); // todo really needed? - sent after every test class
}
public void testSetStarting( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) );
+ target.testSetStarting( report, trim );
}
public void testSetCompleted( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) );
+ target.testSetCompleted( report, trim );
}
public void testStarting( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_STARTING, report, testSetChannelId ) );
+ target.testStarting( report, trim );
}
public void testSucceeded( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_SUCCEEDED, report, testSetChannelId ) );
+ target.testSucceeded( report, trim );
}
public void testAssumptionFailure( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_ASSUMPTIONFAILURE, report, testSetChannelId ) );
+ target.testAssumptionFailure( report, trim );
}
public void testError( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_ERROR, report, testSetChannelId ) );
+ target.testError( report, trim );
}
public void testFailed( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_FAILED, report, testSetChannelId ) );
+ target.testFailed( report, trim );
}
public void testSkipped( ReportEntry report )
{
- encodeAndWriteToTarget( toString( BOOTERCODE_TEST_SKIPPED, report, testSetChannelId ) );
+ target.testSkipped( report, trim );
}
public void testExecutionSkippedByUser()
{
- encodeAndWriteToTarget( toString( BOOTERCODE_STOP_ON_NEXT_TEST, new SimpleReportEntry(), testSetChannelId ) );
- }
-
- void sendProps()
- {
- Properties systemProperties = System.getProperties();
-
- if ( systemProperties != null )
- {
- for ( final String key : systemProperties.stringPropertyNames() )
- {
- String value = systemProperties.getProperty( key );
- encodeAndWriteToTarget( toPropertyString( key, value == null ? "null" : value ) );
- }
- }
+ target.stopOnNextTest();
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public RunMode markAs( RunMode currentRunMode )
{
- byte[] header = stdout ? stdOutHeader : stdErrHeader;
- byte[] content =
- new byte[buf.length * 3 + 1]; // Hex-escaping can be up to 3 times length of a regular byte.
- int i = escapeBytesToPrintable( content, 0, buf, off, len );
- content[i++] = (byte) '\n';
- byte[] encodeBytes = new byte[header.length + i];
- System.arraycopy( header, 0, encodeBytes, 0, header.length );
- System.arraycopy( content, 0, encodeBytes, header.length, i );
-
- synchronized ( target ) // See notes about synchronization/thread safety in class javadoc
- {
- target.write( encodeBytes, 0, encodeBytes.length );
- target.flush();
- if ( target.checkError() )
- {
- // We MUST NOT throw any exception from this method; otherwise we are in loop and CPU goes up:
- // ForkingRunListener -> Exception -> JUnit Notifier and RunListener -> ForkingRunListener -> Exception
- DumpErrorSingleton.getSingleton()
- .dumpStreamText( "Unexpected IOException with stream: " + new String( buf, off, len ) );
- }
- }
+ RunMode runMode = this.runMode;
+ this.runMode = requireNonNull( currentRunMode );
+ return runMode;
}
- public static byte[] createHeader( byte booterCode, int testSetChannel )
+ void sendProps()
{
- return encodeStringForForkCommunication( String.valueOf( (char) booterCode )
- + ','
- + Integer.toString( testSetChannel, 16 )
- + ',' + defaultCharset().name()
- + ',' );
+ target.sendSystemProperties();
}
- private void log( byte bootCode, String message )
+ public void writeTestOutput( String output, boolean stdout )
{
- if ( message != null )
+ if ( stdout )
{
- StringBuilder sb = new StringBuilder( 7 + message.length() * 5 );
- append( sb, bootCode ); comma( sb );
- append( sb, toHexString( testSetChannelId ) ); comma( sb );
- escapeToPrintable( sb, message );
-
- sb.append( '\n' );
- encodeAndWriteToTarget( sb.toString() );
+ target.stdOut( output );
+ }
+ else
+ {
+ target.stdErr( output );
}
}
public void debug( String message )
{
- log( BOOTERCODE_DEBUG, message );
+ target.debug( message );
}
public void info( String message )
{
- log( BOOTERCODE_CONSOLE, message );
+ target.console( message );
}
public void warning( String message )
{
- log( BOOTERCODE_WARNING, message );
+ target.warning( message );
}
public void error( String message )
{
- log( BOOTERCODE_ERROR, message );
+ target.error( message );
}
public void error( String message, Throwable t )
{
- error( ConsoleLoggerUtils.toString( message, t ) );
+ target.error( message, t );
}
public void error( Throwable t )
@@ -268,137 +161,8 @@ public class ForkingRunListener
error( null, t );
}
- private void encodeAndWriteToTarget( String string )
- {
- byte[] encodeBytes = encodeStringForForkCommunication( string );
- synchronized ( target ) // See notes about synchronization/thread safety in class javadoc
- {
- target.write( encodeBytes, 0, encodeBytes.length );
- target.flush();
- if ( target.checkError() )
- {
- // We MUST NOT throw any exception from this method; otherwise we are in loop and CPU goes up:
- // ForkingRunListener -> Exception -> JUnit Notifier and RunListener -> ForkingRunListener -> Exception
- DumpErrorSingleton.getSingleton().dumpStreamText( "Unexpected IOException: " + string );
- }
- }
- }
-
- private String toPropertyString( String key, String value )
- {
- StringBuilder stringBuilder = new StringBuilder();
-
- append( stringBuilder, BOOTERCODE_SYSPROPS ); comma( stringBuilder );
- append( stringBuilder, toHexString( testSetChannelId ) ); comma( stringBuilder );
-
- escapeToPrintable( stringBuilder, key );
- comma( stringBuilder );
- escapeToPrintable( stringBuilder, value );
- stringBuilder.append( "\n" );
- return stringBuilder.toString();
- }
-
- private String toString( byte operationCode, ReportEntry reportEntry, int testSetChannelId )
- {
- StringBuilder stringBuilder = new StringBuilder();
- append( stringBuilder, operationCode ); comma( stringBuilder );
- append( stringBuilder, toHexString( testSetChannelId ) ); comma( stringBuilder );
-
- nullableEncoding( stringBuilder, reportEntry.getSourceName() );
- comma( stringBuilder );
- nullableEncoding( stringBuilder, reportEntry.getName() );
- comma( stringBuilder );
- nullableEncoding( stringBuilder, reportEntry.getGroup() );
- comma( stringBuilder );
- nullableEncoding( stringBuilder, reportEntry.getMessage() );
- comma( stringBuilder );
- nullableEncoding( stringBuilder, reportEntry.getElapsed() );
- encode( stringBuilder, reportEntry.getStackTraceWriter() );
- stringBuilder.append( "\n" );
- return stringBuilder.toString();
- }
-
- private static void comma( StringBuilder stringBuilder )
- {
- stringBuilder.append( "," );
- }
-
- private ForkingRunListener append( StringBuilder stringBuilder, String message )
- {
- stringBuilder.append( encode( message ) );
- return this;
- }
-
- private ForkingRunListener append( StringBuilder stringBuilder, byte b )
- {
- stringBuilder.append( (char) b );
- return this;
- }
-
- private void nullableEncoding( StringBuilder stringBuilder, Integer source )
- {
- if ( source == null )
- {
- stringBuilder.append( "null" );
- }
- else
- {
- stringBuilder.append( source.toString() );
- }
- }
-
- private String encode( String source )
- {
- return source;
- }
-
-
- private static void nullableEncoding( StringBuilder stringBuilder, String source )
- {
- if ( source == null || source.length() == 0 )
- {
- stringBuilder.append( "null" );
- }
- else
- {
- escapeToPrintable( stringBuilder, source );
- }
- }
-
- private void encode( StringBuilder stringBuilder, StackTraceWriter stackTraceWriter )
- {
- encode( stringBuilder, stackTraceWriter, trimStackTraces );
- }
-
- public static void encode( StringBuilder stringBuilder, StackTraceWriter stackTraceWriter, boolean trimStackTraces )
- {
- if ( stackTraceWriter != null )
- {
- comma( stringBuilder );
- //noinspection ThrowableResultOfMethodCallIgnored
- final SafeThrowable throwable = stackTraceWriter.getThrowable();
- if ( throwable != null )
- {
- String message = throwable.getLocalizedMessage();
- nullableEncoding( stringBuilder, message );
- }
- comma( stringBuilder );
- nullableEncoding( stringBuilder, stackTraceWriter.smartTrimmedStackTrace() );
- comma( stringBuilder );
- nullableEncoding( stringBuilder, trimStackTraces
- ? stackTraceWriter.writeTrimmedTraceToString()
- : stackTraceWriter.writeTraceToString() );
- }
- }
-
public void println( String message )
{
- byte[] buf = message.getBytes();
- println( buf, 0, buf.length );
- }
-
- public void println( byte[] buf, int off, int len )
- {
- writeTestOutput( buf, off, len, true );
+ writeTestOutput( message, true );
}
}
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 f985d26..ceb03fa 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
@@ -21,11 +21,8 @@ package org.apache.maven.surefire.booter;
import java.io.DataInputStream;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import static org.apache.maven.surefire.util.internal.StringUtils.FORK_STREAM_CHARSET_NAME;
-import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
+import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
import static java.lang.String.format;
@@ -47,8 +44,6 @@ public enum MasterProcessCommand
NOOP( 4, Void.class ),
BYE_ACK( 5, Void.class );
- private static final Charset ASCII = Charset.forName( "US-ASCII" );
-
private final int id;
private final Class<?> dataType;
@@ -143,21 +138,13 @@ public enum MasterProcessCommand
String toDataTypeAsString( byte... data )
{
- try
- {
- switch ( this )
- {
- case RUN_CLASS:
- return new String( data, FORK_STREAM_CHARSET_NAME );
- case SHUTDOWN:
- return new String( data, ASCII );
- default:
- return null;
- }
- }
- catch ( UnsupportedEncodingException e )
+ switch ( this )
{
- throw new IllegalStateException( e );
+ case RUN_CLASS:
+ case SHUTDOWN:
+ return new String( data, US_ASCII );
+ default:
+ return null;
}
}
@@ -166,9 +153,8 @@ public enum MasterProcessCommand
switch ( this )
{
case RUN_CLASS:
- return encodeStringForForkCommunication( data );
case SHUTDOWN:
- return data.getBytes( ASCII );
+ return data.getBytes( US_ASCII );
default:
return new byte[0];
}
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 9ef7a94..98040a0 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
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.providerapi;
* under the License.
*/
+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;
@@ -149,4 +150,6 @@ public interface ProviderParameters
Shutdown getShutdown();
Integer getSystemExitTimeout();
+
+ ForkedChannelEncoder getForkedChannelEncoder();
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java
index b583593..283b1eb 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java
@@ -25,7 +25,6 @@ import java.io.PrintStream;
import static java.lang.System.setErr;
import static java.lang.System.setOut;
-import static org.apache.maven.surefire.util.internal.StringUtils.NL;
/**
* Deals with system.out/err.
@@ -56,13 +55,13 @@ public class ConsoleOutputCapture
{
// Note: At this point the supplied "buf" instance is reused, which means
// data must be copied out of the buffer
- target.writeTestOutput( buf, off, len, isStdout );
+ target.writeTestOutput( new String( buf, off, len ), isStdout );
}
public void write( byte[] b )
throws IOException
{
- target.writeTestOutput( b, 0, b.length, isStdout );
+ target.writeTestOutput( new String( b ), isStdout );
}
public void write( int b )
@@ -81,12 +80,7 @@ public class ConsoleOutputCapture
public void println( String s )
{
- if ( s == null )
- {
- s = "null"; // Shamelessly taken from super.print
- }
- final byte[] bytes = ( s + NL ).getBytes();
- target.writeTestOutput( bytes, 0, bytes.length, isStdout );
+ target.writeTestOutput( s == null ? "null" : s, isStdout );
}
public void close()
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
index 06d6414..5019b04 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputReceiver.java
@@ -29,11 +29,9 @@ public interface ConsoleOutputReceiver
/**
* Forwards process output from the running test-case into the reporting system
*
- * @param buf the buffer to write
- * @param off offset
- * @param len len
+ * @param output stdout/sterr output from running tests
* @param stdout Indicates if this is stdout
*/
- void writeTestOutput( byte[] buf, int off, int len, boolean stdout );
+ void writeTestOutput( String output, boolean stdout );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleStream.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleStream.java
index 8a22ef0..22486d4 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleStream.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleStream.java
@@ -1 +1 @@
-package org.apache.maven.surefire.report;
/*
* 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.
*/
/**
* Delegates to {@link System#out}.
*/
public interface ConsoleStream
{
void println( String message );
void println( byte[] buf,
int off, int len );
}
\ No newline at end of file
+package org.apache.maven.surefire.report;
/*
* 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.
*/
/**
* Delegates to {@link System#out}.
*/
public interface ConsoleStream
{
void println( String message );
}
\ No newline at end of file
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/DefaultDirectConsoleReporter.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/DefaultDirectConsoleReporter.java
index f1e0f48..842a745 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/DefaultDirectConsoleReporter.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/DefaultDirectConsoleReporter.java
@@ -38,9 +38,4 @@ public final class DefaultDirectConsoleReporter
{
systemOut.println( message );
}
-
- public void println( byte[] buf, int off, int len )
- {
- println( new String( buf, off, len ) );
- }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
index b964430..74e8e9b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
@@ -93,4 +93,13 @@ public interface RunListener
* (The event is fired after the Nth test failed to signal skipping the rest of test-set.)
*/
void testExecutionSkippedByUser();
+
+ /**
+ * Marks the listener with run mode, e.g. normal run or re-run.
+ *
+ * @param currentRunMode set current run
+ * @return previous run mode; never returns null
+ * @throws NullPointerException if <code>currentRunMode</code> is null
+ */
+ RunMode markAs( RunMode currentRunMode );
}
diff --git a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
similarity index 53%
copy from surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
copy to surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
index 7eca90b..0323d9a 100644
--- a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.surefire.log.api;
+package org.apache.maven.surefire.report;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,37 +19,42 @@ package org.apache.maven.plugin.surefire.log.api;
* under the License.
*/
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Collections.unmodifiableMap;
/**
+ * Determines the purpose the provider started the tests. It can be either normal run or re-run.
+ *
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 2.20
+ * @since 2.20.1
*/
-public final class ConsoleLoggerUtils
+public enum RunMode
{
- private ConsoleLoggerUtils()
- {
- throw new IllegalStateException( "non instantiable constructor" );
- }
+ NORMAL_RUN( "normal-run" ), RERUN( "re-run" );
- public static String toString( String message, Throwable t )
+ public static final Map<String, RunMode> MODES = modes();
+
+ private static Map<String, RunMode> modes()
{
- StringWriter result = new StringWriter( 512 );
- PrintWriter writer = new PrintWriter( result );
- try
- {
- if ( message != null )
- {
- writer.println( message );
- }
- t.printStackTrace( writer );
- writer.flush();
- return result.toString();
- }
- finally
+ Map<String, RunMode> modes = new ConcurrentHashMap<String, RunMode>();
+ for ( RunMode mode : values() )
{
- writer.close();
+ modes.put( mode.geRunName(), mode );
}
+ return unmodifiableMap( modes );
+ }
+
+ private final String runName;
+
+ RunMode( String runName )
+ {
+ this.runName = runName;
+ }
+
+ public String geRunName()
+ {
+ return runName;
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
index e2ae963..66cef8d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
@@ -74,7 +74,7 @@ public class TestListResolver
for ( String request : split( csvTests, "," ) )
{
request = request.trim();
- if ( request.length() != 0 && !request.equals( "!" ) )
+ if ( !request.isEmpty() && !request.equals( "!" ) )
{
resolveTestRequest( request, patterns, includedFilters, excludedFilters );
}
@@ -249,7 +249,7 @@ public class TestListResolver
}
aggregatedTest += aggregatedTest( "!", getExcludedPatterns() );
- return aggregatedTest.length() == 0 ? "" : aggregatedTest;
+ return aggregatedTest.isEmpty() ? "" : aggregatedTest;
}
public Set<ResolvedTest> getIncludedPatterns()
@@ -309,7 +309,7 @@ public class TestListResolver
static String removeExclamationMark( String s )
{
- return s.length() != 0 && s.charAt( 0 ) == '!' ? s.substring( 1 ) : s;
+ return !s.isEmpty() && s.charAt( 0 ) == '!' ? s.substring( 1 ) : s;
}
private static void updatedFilters( boolean isExcluded, ResolvedTest test, IncludedExcludedPatterns patterns,
@@ -334,7 +334,7 @@ public class TestListResolver
for ( ResolvedTest test : tests )
{
String readableTest = test.toString();
- if ( readableTest.length() != 0 )
+ if ( !readableTest.isEmpty() )
{
if ( aggregatedTest.length() != 0 )
{
@@ -357,7 +357,7 @@ public class TestListResolver
if ( exc != null )
{
exc = exc.trim();
- if ( exc.length() != 0 )
+ if ( !exc.isEmpty() )
{
if ( exc.contains( "!" ) )
{
@@ -457,8 +457,8 @@ public class TestListResolver
if ( isRegexPrefixedPattern( request ) )
{
final String[] unwrapped = unwrapRegex( request );
- final boolean hasClass = unwrapped[0].length() != 0;
- final boolean hasMethod = unwrapped[1].length() != 0;
+ final boolean hasClass = !unwrapped[0].isEmpty();
+ final boolean hasMethod = !unwrapped[1].isEmpty();
if ( hasClass && hasMethod )
{
test = new ResolvedTest( unwrapped[0], unwrapped[1], true );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java
index d1838b2..44410de 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java
@@ -19,11 +19,6 @@ package org.apache.maven.surefire.util.internal;
* under the License.
*/
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
import java.util.StringTokenizer;
/**
@@ -62,8 +57,6 @@ public final class StringUtils
private static final byte[] HEX_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- private static final Charset DEFAULT_CHARSET = Charset.defaultCharset();
-
// 8-bit charset Latin-1
public static final String FORK_STREAM_CHARSET_NAME = "ISO-8859-1";
@@ -148,216 +141,6 @@ public final class StringUtils
}
/**
- * Escape the specified string to a representation that only consists of nicely printable characters, without any
- * newlines and without a comma.
- * <p>
- * The reverse-method is {@link #unescapeString(StringBuilder, CharSequence)}.
- *
- * @param target target string buffer. The required space will be up to {@code str.getBytes().length * 5} chars.
- * @param str String to escape values in, may be {@code null}.
- */
- @SuppressWarnings( "checkstyle:magicnumber" )
- public static void escapeToPrintable( StringBuilder target, CharSequence str )
- {
- if ( target == null )
- {
- throw new IllegalArgumentException( "The target buffer must not be null" );
- }
- if ( str == null )
- {
- return;
- }
-
- for ( int i = 0; i < str.length(); i++ )
- {
- char c = str.charAt( i );
-
- // handle non-nicely printable chars and the comma
- if ( c < 32 || c > 126 || c == '\\' || c == ',' )
- {
- target.append( '\\' );
- target.append( (char) HEX_CHARS[( 0xF000 & c ) >> 12] );
- target.append( (char) HEX_CHARS[( 0x0F00 & c ) >> 8] );
- target.append( (char) HEX_CHARS[( 0x00F0 & c ) >> 4] );
- target.append( (char) HEX_CHARS[( 0x000F & c )] );
- }
- else
- {
- target.append( c );
- }
- }
- }
-
- /**
- * Reverses the effect of {@link #escapeToPrintable(StringBuilder, CharSequence)}.
- *
- * @param target target string buffer
- * @param str the String to un-escape, as created by {@link #escapeToPrintable(StringBuilder, CharSequence)}
- */
- public static void unescapeString( StringBuilder target, CharSequence str )
- {
- if ( target == null )
- {
- throw new IllegalArgumentException( "The target buffer must not be null" );
- }
- if ( str == null )
- {
- return;
- }
-
- for ( int i = 0; i < str.length(); i++ )
- {
- char ch = str.charAt( i );
-
- if ( ch == '\\' )
- {
- target.append( (char) (
- digit( str.charAt( ++i ) ) << 12
- | digit( str.charAt( ++i ) ) << 8
- | digit( str.charAt( ++i ) ) << 4
- | digit( str.charAt( ++i ) )
- ) );
- }
- else
- {
- target.append( ch );
- }
- }
- }
-
- private static int digit( char ch )
- {
- if ( ch >= 'a' )
- {
- return 10 + ch - 'a';
- }
- else if ( ch >= 'A' )
- {
- return 10 + ch - 'A';
- }
- else
- {
- return ch - '0';
- }
- }
-
- /**
- * Escapes the bytes in the array {@code str} to contain only 'printable' bytes.
- * <p>
- * Escaping is done by encoding the non-nicely printable bytes to {@code '\' + upperCaseHexBytes(byte)}.
- * <p>
- * A save length of {@code out} is {@code len * 3 + outoff}.
- * <p>
- * The reverse-method is {@link #unescapeBytes(byte[], String)}.
- *
- * @param out output buffer
- * @param outoff offset in the output buffer
- * @param input input buffer
- * @param off offset in the input buffer
- * @param len number of bytes to copy from the input buffer
- * @return number of bytes written to {@code out}
- */
- @SuppressWarnings( "checkstyle:magicnumber" )
- public static int escapeBytesToPrintable( byte[] out, int outoff, byte[] input, int off, int len )
- {
- if ( out == null )
- {
- throw new IllegalArgumentException( "The output array must not be null" );
- }
- if ( input == null || input.length == 0 )
- {
- return 0;
- }
- int outputPos = outoff;
- int end = off + len;
- for ( int i = off; i < end; i++ )
- {
- byte b = input[i];
-
- // handle non-nicely printable bytes
- if ( b < 32 || b > 126 || b == '\\' || b == ',' )
- {
- int upper = ( 0xF0 & b ) >> 4;
- int lower = ( 0x0F & b );
- out[outputPos++] = '\\';
- out[outputPos++] = HEX_CHARS[upper];
- out[outputPos++] = HEX_CHARS[lower];
- }
- else
- {
- out[outputPos++] = b;
- }
- }
-
- return outputPos - outoff;
- }
-
- /**
- * Reverses the effect of {@link #escapeBytesToPrintable(byte[], int, byte[], int, int)}.
- *
- * @param str the input String
- * @param charsetName the charset name
- * @return the number of bytes written to {@code out}
- */
- public static ByteBuffer unescapeBytes( String str, String charsetName )
- {
- int outPos = 0;
-
- if ( str == null )
- {
- return ByteBuffer.wrap( new byte[0] );
- }
-
- byte[] out = new byte[str.length()];
- for ( int i = 0; i < str.length(); i++ )
- {
- char ch = str.charAt( i );
-
- if ( ch == '\\' )
- {
- int upper = digit( str.charAt( ++i ) );
- int lower = digit( str.charAt( ++i ) );
- out[outPos++] = (byte) ( upper << 4 | lower );
- }
- else
- {
- out[outPos++] = (byte) ch;
- }
- }
-
- Charset sourceCharset = Charset.forName( charsetName );
- if ( !DEFAULT_CHARSET.equals( sourceCharset ) )
- {
- CharBuffer decodedFromSourceCharset;
- try
- {
- decodedFromSourceCharset = sourceCharset.newDecoder().decode( ByteBuffer.wrap( out, 0, outPos ) );
- ByteBuffer defaultEncoded = DEFAULT_CHARSET.encode( decodedFromSourceCharset );
-
- return defaultEncoded;
- }
- catch ( CharacterCodingException e )
- {
- // ignore and fall through to the non-recoded version
- }
- }
-
- return ByteBuffer.wrap( out, 0, outPos );
- }
-
- public static byte[] encodeStringForForkCommunication( String string )
- {
- try
- {
- return string.getBytes( FORK_STREAM_CHARSET_NAME );
- }
- catch ( UnsupportedEncodingException e )
- {
- throw new RuntimeException( "The JVM must support Charset " + FORK_STREAM_CHARSET_NAME, e );
- }
- }
-
- /**
*
* @param buffer Examined StringBuffer
* @param pattern a pattern which should start in <code>buffer</code>
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 c43a3a6..d64b5a5 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -39,7 +39,6 @@ import org.apache.maven.surefire.util.TestsToRunTest;
import org.apache.maven.surefire.util.UrlUtilsTest;
import org.apache.maven.surefire.util.internal.ByteBufferTest;
import org.apache.maven.surefire.util.internal.ConcurrencyUtilsTest;
-import org.apache.maven.surefire.util.internal.StringUtilsTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -60,7 +59,6 @@ import org.junit.runners.Suite;
TestListResolverTest.class,
ByteBufferTest.class,
ConcurrencyUtilsTest.class,
- StringUtilsTest.class,
DefaultDirectoryScannerTest.class,
RunOrderCalculatorTest.class,
RunOrderTest.class,
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkedChannelEncoderTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkedChannelEncoderTest.java
new file mode 100644
index 0000000..a52727d
--- /dev/null
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkedChannelEncoderTest.java
@@ -0,0 +1,481 @@
+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.ReportEntry;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import static java.nio.charset.Charset.defaultCharset;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.maven.surefire.booter.ForkedChannelEncoder.encode;
+import static org.apache.maven.surefire.booter.ForkedChannelEncoder.encodeHeader;
+import static org.apache.maven.surefire.booter.ForkedChannelEncoder.encodeMessage;
+import static org.apache.maven.surefire.booter.ForkedChannelEncoder.encodeOpcode;
+import static org.apache.maven.surefire.booter.ForkedChannelEncoder.print;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.MAGIC_NUMBER;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public class ForkedChannelEncoderTest
+{
+
+ @Test
+ public void shouldBeFailSafe()
+ {
+ Charset encoding = Charset.defaultCharset();
+ assertThat( ForkedChannelEncoder.toBase64( null, encoding ) ).isEqualTo( "-" );
+ assertThat( ForkedChannelEncoder.base64WithUtf8( null ) ).isEqualTo( "-" );
+ StringBuilder builder = new StringBuilder();
+ ForkedChannelEncoder.base64WithUtf8( builder, null );
+ assertThat( builder.toString() ).isEqualTo( "-" );
+ }
+
+ @Test
+ public void shouldHaveSystemProperty()
+ {
+ StringBuilder actualEncoded = encode( BOOTERCODE_SYSPROPS, NORMAL_RUN, "arg1", "arg2" );
+ String expected = MAGIC_NUMBER + "normal-run:" + BOOTERCODE_SYSPROPS.getOpcode() + ":UTF-8:YXJnMQ==:YXJnMg==";
+
+ assertThat( actualEncoded.toString() )
+ .isEqualTo( expected );
+ }
+
+ @Test
+ public void safeThrowableShouldBeEncoded()
+ {
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ final String exceptionMessage = "msg";
+ final String encodedExceptionMsg = printBase64Binary( toArray( utf8.encode( exceptionMessage ) ) );
+
+ final String smartStackTrace = "MyTest:86 >> Error";
+ final String encodedSmartStackTrace = printBase64Binary( toArray( utf8.encode( smartStackTrace ) ) );
+
+ final String stackTrace = "trace line 1\ntrace line 2";
+ final String encodedStackTrace = printBase64Binary( toArray( utf8.encode( stackTrace ) ) );
+
+ final String trimmedStackTrace = "trace line 1\ntrace line 2";
+ final String encodedTrimmedStackTrace = printBase64Binary( toArray( utf8.encode( trimmedStackTrace ) ) );
+
+ SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
+
+ StringBuilder encoded = new StringBuilder();
+ encode( encoded, stackTraceWriter, false );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":" + encodedExceptionMsg + ":" + encodedSmartStackTrace + ":" + encodedStackTrace );
+
+ encoded = new StringBuilder();
+ encode( encoded, stackTraceWriter, true );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":" + encodedExceptionMsg + ":" + encodedSmartStackTrace + ":" + encodedTrimmedStackTrace );
+ }
+
+ @Test
+ public void emptySafeThrowable()
+ {
+ SafeThrowable safeThrowable = new SafeThrowable( new Exception( "" ) );
+
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "" );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( "" );
+
+ StringBuilder encoded = new StringBuilder();
+ encode( encoded, stackTraceWriter, false );
+
+ assertThat( encoded.toString() )
+ .isEqualTo( ":::" );
+ }
+
+ @Test
+ public void nullSafeThrowable()
+ {
+ SafeThrowable safeThrowable = new SafeThrowable( new Exception() );
+
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+
+ StringBuilder encoded = new StringBuilder();
+ encode( encoded, stackTraceWriter, false );
+
+ assertThat( encoded.toString() )
+ .isEqualTo( ":-:-:-" );
+ }
+
+ @Test
+ public void reportEntry() throws IOException
+ {
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ final String exceptionMessage = "msg";
+ final String encodedExceptionMsg = printBase64Binary( toArray( utf8.encode( exceptionMessage ) ) );
+
+ final String smartStackTrace = "MyTest:86 >> Error";
+ final String encodedSmartStackTrace = printBase64Binary( toArray( utf8.encode( smartStackTrace ) ) );
+
+ final String stackTrace = "trace line 1\ntrace line 2";
+ final String encodedStackTrace = printBase64Binary( toArray( utf8.encode( stackTrace ) ) );
+
+ final String trimmedStackTrace = "trace line 1\ntrace line 2";
+ final String encodedTrimmedStackTrace = printBase64Binary( toArray( utf8.encode( trimmedStackTrace ) ) );
+
+ SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
+
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( 102 );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( "skipped test" );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ String encodedSourceName = printBase64Binary( toArray( utf8.encode( reportEntry.getSourceName() ) ) );
+ String encodedName = printBase64Binary( toArray( utf8.encode( reportEntry.getName() ) ) );
+ String encodedGroup = printBase64Binary( toArray( utf8.encode( reportEntry.getGroup() ) ) );
+ String encodedMessage = printBase64Binary( toArray( utf8.encode( reportEntry.getMessage() ) ) );
+
+ StringBuilder encode = encode( "X", "normal-run", reportEntry, false );
+ assertThat( encode.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:X:UTF-8:"
+ + encodedSourceName
+ + ":"
+ + encodedName
+ + ":"
+ + encodedGroup
+ + ":"
+ + encodedMessage
+ + ":"
+ + 102
+ + ":"
+
+ + encodedExceptionMsg
+ + ":"
+ + encodedSmartStackTrace
+ + ":"
+ + encodedStackTrace
+ );
+
+ encode = encode( "X", "normal-run", reportEntry, true );
+ assertThat( encode.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:X:UTF-8:"
+ + encodedSourceName
+ + ":"
+ + encodedName
+ + ":"
+ + encodedGroup
+ + ":"
+ + encodedMessage
+ + ":"
+ + 102
+ + ":"
+
+ + encodedExceptionMsg
+ + ":"
+ + encodedSmartStackTrace
+ + ":"
+ + encodedTrimmedStackTrace
+ );
+
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.testSetStarting( reportEntry, true );
+ LineNumberReader printedLines = out.newReader( defaultCharset() );
+ assertThat( printedLines.readLine() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:testset-starting:UTF-8:"
+ + encodedSourceName
+ + ":"
+ + encodedName
+ + ":"
+ + encodedGroup
+ + ":"
+ + encodedMessage
+ + ":"
+ + 102
+ + ":"
+
+ + encodedExceptionMsg
+ + ":"
+ + encodedSmartStackTrace
+ + ":"
+ + encodedTrimmedStackTrace
+ );
+ assertThat( printedLines.readLine() ).isNull();
+
+ out = Stream.newStream();
+ forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.testSetStarting( reportEntry, false );
+ printedLines = out.newReader( defaultCharset() );
+ assertThat( printedLines.readLine() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:testset-starting:UTF-8:"
+ + encodedSourceName
+ + ":"
+ + encodedName
+ + ":"
+ + encodedGroup
+ + ":"
+ + encodedMessage
+ + ":"
+ + 102
+ + ":"
+
+ + encodedExceptionMsg
+ + ":"
+ + encodedSmartStackTrace
+ + ":"
+ + encodedStackTrace
+ );
+ assertThat( printedLines.readLine() ).isNull();
+ }
+
+ @Test
+ public void testSendOpcode()
+ {
+ StringBuilder encoded = encodeOpcode( "normal-run", "some-opcode" );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:some-opcode" );
+
+ encoded = encodeHeader( "some-opcode", "normal-run", Charset.forName( "UTF-8" ) );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:some-opcode:UTF-8" );
+
+ encoded = encodeMessage( "some-opcode", "normal-run", Charset.forName( "UTF-8" ), "msg" );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:some-opcode:UTF-8:msg" );
+
+ encoded = print( "some-opcode", "normal-run", Charset.forName( "UTF-8" ), "msg" );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:some-opcode:UTF-8:bXNn" );
+
+ encoded = print( "some-opcode", "normal-run", Charset.forName( "UTF-8" ), new String[] { null } );
+ assertThat( encoded.toString() )
+ .isEqualTo( ":maven:surefire:std:out:normal-run:some-opcode:UTF-8:-" );
+ }
+
+ @Test
+ public void testConsole()
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.console( "msg" );
+
+ String encoded = new String( out.toByteArray(), defaultCharset() );
+
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ String expected = ":maven:surefire:std:out:normal-run:console:UTF-8:"
+ + printBase64Binary( toArray( utf8.encode( "msg" ) ) )
+ + "\n";
+
+ assertThat( encoded )
+ .isEqualTo( expected );
+ }
+
+ @Test
+ public void testError()
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.error( "msg" );
+
+ String encoded = new String( out.toByteArray(), defaultCharset() );
+
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ String expected = ":maven:surefire:std:out:normal-run:error:UTF-8:"
+ + printBase64Binary( toArray( utf8.encode( "msg" ) ) )
+ + "\n";
+
+ assertThat( encoded )
+ .isEqualTo( expected );
+ }
+
+ @Test
+ public void testDebug()
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.debug( "msg" );
+
+ String encoded = new String( out.toByteArray(), defaultCharset() );
+
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ String expected = ":maven:surefire:std:out:normal-run:debug:UTF-8:"
+ + printBase64Binary( toArray( utf8.encode( "msg" ) ) )
+ + "\n";
+
+ assertThat( encoded )
+ .isEqualTo( expected );
+ }
+
+ @Test
+ public void testWarning()
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ forkedChannelEncoder.warning( "msg" );
+
+ String encoded = new String( out.toByteArray(), defaultCharset() );
+
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ String expected = ":maven:surefire:std:out:normal-run:warning:UTF-8:"
+ + printBase64Binary( toArray( utf8.encode( "msg" ) ) )
+ + "\n";
+
+ assertThat( encoded )
+ .isEqualTo( expected );
+ }
+
+ @Test
+ public void testStdOutStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "UTF-8" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdOut( msgArray, 0, msgArray.length );
+
+ String expected = ":maven:surefire:std:out:normal-run:std-out-stream:" + encoding.name() + ":"
+ + printBase64Binary( msgArray );
+
+ LineNumberReader printedLines = out.newReader( defaultCharset() );
+ assertThat( printedLines.readLine() )
+ .isEqualTo( expected );
+ assertThat( printedLines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testStdErrStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdErr( msgArray, 0, msgArray.length );
+
+ String expected = ":maven:surefire:std:out:normal-run:std-err-stream:" + encoding.name() + ":"
+ + printBase64Binary( msgArray );
+
+ LineNumberReader printedLines = out.newReader( defaultCharset() );
+ assertThat( printedLines.readLine() )
+ .isEqualTo( expected );
+ assertThat( printedLines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldCountSameNumberOfSystemProperties() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ int expectedSize = System.getProperties().size();
+ forkedChannelEncoder.sendSystemProperties();
+
+ LineNumberReader printedLines = out.newReader( streamEncoding );
+
+ int size = 0;
+ for ( String line; ( line = printedLines.readLine() ) != null; size++ )
+ {
+ assertThat( line )
+ .startsWith( ":maven:surefire:std:out:normal-run:sys-prop:UTF-8:" );
+ }
+
+ assertThat( size )
+ .isEqualTo( expectedSize );
+ }
+
+ private static class Stream extends PrintStream
+ {
+ private final ByteArrayOutputStream out;
+
+ public Stream( ByteArrayOutputStream out )
+ {
+ super( out, true );
+ this.out = out;
+ }
+
+ byte[] toByteArray()
+ {
+ return out.toByteArray();
+ }
+
+ LineNumberReader newReader( Charset streamCharset )
+ {
+ return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
+ }
+
+ static Stream newStream()
+ {
+ return new Stream( new ByteArrayOutputStream() );
+ }
+ }
+
+ private static byte[] toArray( ByteBuffer buffer )
+ {
+ return Arrays.copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
+ }
+
+}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
index b71eda2..4b6d891 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
@@ -34,7 +34,7 @@ public class ForkingRunListenerTest
{
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream target = new PrintStream( byteArrayOutputStream );
- ForkingRunListener forkingRunListener = new ForkingRunListener( target, 1, true );
+ ForkingRunListener forkingRunListener = new ForkingRunListener( new ForkedChannelEncoder( target ), true );
forkingRunListener.info( new String( new byte[]{ 65 } ) );
forkingRunListener.info( new String( new byte[]{ } ) );
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java
deleted file mode 100644
index c1c8d73..0000000
--- a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.apache.maven.surefire.util.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.charset.Charset;
-
-import junit.framework.TestCase;
-
-/**
- * @author Andreas Gudian
- */
-public class StringUtilsTest
- extends TestCase
-{
-
- public void testUnescapeString()
- {
- CharSequence inputString = createInputString();
-
- StringBuilder escaped = new StringBuilder( inputString.length() * 5 );
- int initialCapacity = escaped.capacity();
-
- StringUtils.escapeToPrintable( escaped, inputString );
-
- assertEquals( initialCapacity, escaped.capacity() );
-
- StringBuilder unescaped = new StringBuilder( inputString.length() );
- StringUtils.unescapeString( unescaped, escaped );
-
- assertEquals( inputString.length(), unescaped.length() );
-
- for ( int i = 0; i < inputString.length(); i++ )
- {
- if ( inputString.charAt( i ) != unescaped.charAt( i ) )
- {
- fail( "Input and Unescaped String are not equal at position " + i );
- }
- }
- }
-
- private CharSequence createInputString()
- {
- StringBuilder sb = new StringBuilder();
- for ( int i = 0; i < Character.MAX_CODE_POINT; i++ )
- {
- sb.appendCodePoint( i );
- }
-
- return sb;
- }
-
- public void testUnescapeBytes()
- {
- byte[] input = new byte[256];
-
- for ( int i = 0; i <= 0xFF; i++ )
- {
- byte b = (byte) ( 0xFF & i );
- input[i] = b;
- }
-
- byte[] escaped = new byte[input.length * 3];
-
- int escapedBytes = StringUtils.escapeBytesToPrintable( escaped, 0, input, 0, input.length );
-
- String escapedString = new String( escaped, 0, escapedBytes );
-
- assertEquals( escapedBytes, escapedString.length() );
-
- java.nio.ByteBuffer unescaped = StringUtils.unescapeBytes( escapedString, Charset.defaultCharset().name() );
-
- assertEquals( input.length, unescaped.remaining() - unescaped.position() );
-
- for ( int i = 0; i < input.length; i++ )
- {
- assertEquals( "At position " + i, input[i], unescaped.get() );
- }
- }
-}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
index e7d97c8..cc1f0eb 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
@@ -84,7 +84,7 @@ public class Classpath implements Iterable<String>
for ( String element : elements )
{
element = element.trim();
- if ( element.length() != 0 )
+ if ( !element.isEmpty() )
{
newCp.add( element );
}
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 fef21d1..caa99b6 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
@@ -23,7 +23,6 @@ import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
import org.apache.maven.surefire.report.ReporterFactory;
-import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.testset.TestSetFailedException;
@@ -49,13 +48,9 @@ import static java.lang.Thread.currentThread;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.maven.surefire.booter.CommandReader.getReader;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_BYE;
-import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_ERROR;
-import static org.apache.maven.surefire.booter.ForkingRunListener.encode;
import static org.apache.maven.surefire.booter.SystemPropertyManager.setSystemProperties;
import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
-import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
/**
* The part of the booter that is unique to a forked vm.
@@ -87,7 +82,7 @@ public final class ForkedBooter
{
final CommandReader reader = startupMasterProcessReader();
final ScheduledFuture<?> pingScheduler = listenToShutdownCommands( reader );
- final PrintStream originalOut = out;
+ final ForkedChannelEncoder eventChannel = new ForkedChannelEncoder( out );
try
{
final String tmpDir = args[0];
@@ -128,7 +123,7 @@ public final class ForkedBooter
}
else if ( readTestsFromInputStream )
{
- testSet = new LazyTestsToRun( originalOut );
+ testSet = new LazyTestsToRun( eventChannel );
}
else
{
@@ -137,26 +132,20 @@ public final class ForkedBooter
try
{
- runSuitesInProcess( testSet, startupConfiguration, providerConfiguration, originalOut );
+ runSuitesInProcess( testSet, startupConfiguration, providerConfiguration, eventChannel );
}
catch ( InvocationTargetException t )
{
+ Throwable e = t.getTargetException();
DumpErrorSingleton.getSingleton().dumpException( t );
- StackTraceWriter stackTraceWriter =
- new LegacyPojoStackTraceWriter( "test subsystem", "no method", t.getTargetException() );
- StringBuilder stringBuilder = new StringBuilder();
- encode( stringBuilder, stackTraceWriter, false );
- encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n" , originalOut );
+ eventChannel.error( new LegacyPojoStackTraceWriter( "test subsystem", "no method", e ), false );
}
catch ( Throwable t )
{
DumpErrorSingleton.getSingleton().dumpException( t );
- StackTraceWriter stackTraceWriter = new LegacyPojoStackTraceWriter( "test subsystem", "no method", t );
- StringBuilder stringBuilder = new StringBuilder();
- encode( stringBuilder, stackTraceWriter, false );
- encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n", originalOut );
+ eventChannel.error( new LegacyPojoStackTraceWriter( "test subsystem", "no method", t ), false );
}
- acknowledgedExit( reader, originalOut );
+ acknowledgedExit( reader, eventChannel );
}
catch ( Throwable t )
{
@@ -233,17 +222,6 @@ public final class ForkedBooter
};
}
- private static void encodeAndWriteToOutput( String string, PrintStream out )
- {
- byte[] encodeBytes = encodeStringForForkCommunication( string );
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized ( out )
- {
- out.write( encodeBytes, 0, encodeBytes.length );
- out.flush();
- }
- }
-
private static void kill()
{
Runtime.getRuntime().halt( 1 );
@@ -255,7 +233,7 @@ public final class ForkedBooter
System.exit( returnCode );
}
- private static void acknowledgedExit( CommandReader reader, PrintStream originalOut )
+ private static void acknowledgedExit( CommandReader reader, ForkedChannelEncoder eventChannel )
{
final Semaphore barrier = new Semaphore( 0 );
reader.addByeAckListener( new CommandListener()
@@ -267,7 +245,7 @@ public final class ForkedBooter
}
}
);
- encodeAndWriteToOutput( ( (char) BOOTERCODE_BYE ) + ",0,BYE!\n", originalOut );
+ eventChannel.bye();
launchLastDitchDaemonShutdownThread( 0 );
long timeoutMillis = max( systemExitTimeoutInSeconds * ONE_SECOND_IN_MILLIS, ONE_SECOND_IN_MILLIS );
acquireOnePermit( barrier, timeoutMillis );
@@ -288,20 +266,20 @@ public final class ForkedBooter
private static RunResult runSuitesInProcess( Object testSet, StartupConfiguration startupConfiguration,
ProviderConfiguration providerConfiguration,
- PrintStream originalSystemOut )
+ ForkedChannelEncoder eventChannel )
throws SurefireExecutionException, TestSetFailedException, InvocationTargetException
{
- final ReporterFactory factory = createForkingReporterFactory( providerConfiguration, originalSystemOut );
+ final ReporterFactory factory = createForkingReporterFactory( providerConfiguration, eventChannel );
return invokeProviderInSameClassLoader( testSet, factory, providerConfiguration, true, startupConfiguration,
- false );
+ false, eventChannel );
}
private static ReporterFactory createForkingReporterFactory( ProviderConfiguration providerConfiguration,
- PrintStream originalSystemOut )
+ ForkedChannelEncoder eventChannel )
{
final boolean trimStackTrace = providerConfiguration.getReporterConfiguration().isTrimStackTrace();
- return new ForkingReporterFactory( trimStackTrace, originalSystemOut );
+ return new ForkingReporterFactory( trimStackTrace, eventChannel );
}
private static synchronized ScheduledThreadPoolExecutor getJvmTerminator()
@@ -346,7 +324,8 @@ public final class ForkedBooter
ProviderConfiguration providerConfig,
boolean insideFork,
StartupConfiguration startupConfig,
- boolean restoreStreams )
+ boolean restoreStreams,
+ ForkedChannelEncoder forkedChannelEncoder )
throws TestSetFailedException, InvocationTargetException
{
final PrintStream orgSystemOut = out;
@@ -356,8 +335,8 @@ public final class ForkedBooter
try
{
- return createProviderInCurrentClassloader( startupConfig, insideFork, providerConfig, factory )
- .invoke( testSet );
+ return createProviderInCurrentClassloader( startupConfig, insideFork, providerConfig, factory,
+ forkedChannelEncoder ).invoke( testSet );
}
finally
{
@@ -371,12 +350,14 @@ public final class ForkedBooter
private static SurefireProvider createProviderInCurrentClassloader( StartupConfiguration startupConfiguration,
boolean isInsideFork,
- ProviderConfiguration providerConfiguration,
- Object reporterManagerFactory )
+ ProviderConfiguration providerConfiguration,
+ Object reporterManagerFactory,
+ ForkedChannelEncoder forkedChannelEncoder )
{
BaseProviderFactory bpf = new BaseProviderFactory( (ReporterFactory) reporterManagerFactory, isInsideFork );
bpf.setTestRequest( providerConfiguration.getTestSuiteDefinition() );
bpf.setReporterConfiguration( providerConfiguration.getReporterConfiguration() );
+ bpf.setForkedChannelEncoder( forkedChannelEncoder );
ClassLoader classLoader = currentThread().getContextClassLoader();
bpf.setClassLoaders( classLoader );
bpf.setTestArtifactInfo( providerConfiguration.getTestArtifact() );
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 29a59b6..dac922a 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
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.PrintStream;
import java.util.Collections;
import java.util.Iterator;
@@ -44,24 +43,24 @@ import static org.apache.maven.surefire.util.ReflectionUtils.loadClass;
final class LazyTestsToRun
extends TestsToRun
{
- private final PrintStream originalOutStream;
+ private final ForkedChannelEncoder eventChannel;
/**
* C'tor
*
- * @param originalOutStream the output stream to use when requesting new new tests
+ * @param eventChannel the output stream to use when requesting new new tests
*/
- LazyTestsToRun( PrintStream originalOutStream )
+ LazyTestsToRun( ForkedChannelEncoder eventChannel )
{
super( Collections.<Class<?>>emptySet() );
- this.originalOutStream = originalOutStream;
+ this.eventChannel = eventChannel;
}
private final class BlockingIterator
implements Iterator<Class<?>>
{
- private final Iterator<String> it = getReader().getIterableClasses( originalOutStream ).iterator();
+ private final Iterator<String> it = getReader().getIterableClasses( eventChannel ).iterator();
public boolean hasNext()
{
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/TypeEncodedValue.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/TypeEncodedValue.java
index bbd0f70..606e76b 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/TypeEncodedValue.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/TypeEncodedValue.java
@@ -51,8 +51,8 @@ public class TypeEncodedValue
public Object getDecodedValue( ClassLoader classLoader )
{
- // todo: use jdk6 switch case
- if ( type.trim().length() == 0 )
+ // todo: use jdk7 switch case
+ if ( type.trim().isEmpty() )
{
return null;
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index b731dc0..6db8339 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -94,7 +94,7 @@ public class CommandReaderTest
@Test
public void readJustOneClass() throws Exception
{
- Iterator<String> it = reader.getIterableClasses( nul() ).iterator();
+ Iterator<String> it = reader.getIterableClasses( new ForkedChannelEncoder( nul() ) ).iterator();
assertTrue( it.hasNext() );
assertThat( it.next(), is( getClass().getName() ) );
reader.stop();
@@ -113,7 +113,7 @@ public class CommandReaderTest
@Test
public void manyClasses() throws Exception
{
- Iterator<String> it1 = reader.getIterableClasses( nul() ).iterator();
+ Iterator<String> it1 = reader.getIterableClasses( new ForkedChannelEncoder( nul() ) ).iterator();
assertThat( it1.next(), is( getClass().getName() ) );
addTestToPipeline( A.class.getName() );
assertThat( it1.next(), is( A.class.getName() ) );
@@ -129,7 +129,7 @@ public class CommandReaderTest
@Test
public void twoIterators() throws Exception
{
- Iterator<String> it1 = reader.getIterableClasses( nul() ).iterator();
+ Iterator<String> it1 = reader.getIterableClasses(new ForkedChannelEncoder( nul() ) ).iterator();
assertThat( it1.next(), is( getClass().getName() ) );
addTestToPipeline( A.class.getName() );
@@ -162,7 +162,7 @@ public class CommandReaderTest
{
public void run()
{
- Iterator<String> it = reader.getIterableClasses( nul() ).iterator();
+ Iterator<String> it = reader.getIterableClasses( new ForkedChannelEncoder( nul() ) ).iterator();
assertThat( it.next(), is( CommandReaderTest.class.getName() ) );
}
};
@@ -189,7 +189,7 @@ public class CommandReaderTest
{
public void run()
{
- Iterator<String> it = reader.getIterableClasses( nul() ).iterator();
+ Iterator<String> it = reader.getIterableClasses( new ForkedChannelEncoder( nul() ) ).iterator();
assertThat( it.next(), is( CommandReaderTest.class.getName() ) );
counter.countDown();
assertThat( it.next(), is( PropertiesWrapperTest.class.getName() ) );
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
index 4cb162d..78a1450 100755
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/SurefireLauncher.java
@@ -70,7 +70,7 @@ public final class SurefireLauncher
public SurefireLauncher setInProcessJavaHome()
{
String javaHome = System.getenv( "JAVA_HOME" );
- if ( javaHome != null && javaHome.length() > 0 )
+ if ( javaHome != null && !javaHome.isEmpty() )
{
try
{
diff --git a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java b/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
index 7eca90b..b535758 100644
--- a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
+++ b/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtils.java
@@ -33,6 +33,11 @@ public final class ConsoleLoggerUtils
throw new IllegalStateException( "non instantiable constructor" );
}
+ public static String toString( Throwable t )
+ {
+ return toString( null, t );
+ }
+
public static String toString( String message, Throwable t )
{
StringWriter result = new StringWriter( 512 );
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
index 99d7aae..e2c91ac 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
/**
* Internal tests use only.
@@ -87,6 +88,12 @@ public class MockReporter
{
}
+ @Override
+ public RunMode markAs( RunMode currentRunMode )
+ {
+ return null;
+ }
+
public void testSkippedByUser( ReportEntry report )
{
testSkipped( report );
diff --git a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/RequestedTest.java b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/RequestedTest.java
index 0eca387..52c2d52 100644
--- a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/RequestedTest.java
+++ b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/RequestedTest.java
@@ -59,7 +59,7 @@ final class RequestedTest
public String describe()
{
String description = test.toString();
- return description.length() == 0 ? "*" : description;
+ return description.isEmpty() ? "*" : description;
}
@Override
diff --git a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
index 9ca397e..a8071cb 100644
--- a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
+++ b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
@@ -24,6 +24,7 @@ import java.util.List;
import org.apache.maven.surefire.common.junit3.JUnit3Reflector;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.testset.TestSetFailedException;
import junit.framework.Test;
@@ -104,6 +105,11 @@ public class JUnitTestSetTest
{
}
+ public RunMode markAs( RunMode currentRunMode )
+ {
+ return RunMode.NORMAL_RUN;
+ }
+
public void testSkippedByUser( ReportEntry report )
{
testSkipped( report );
diff --git a/surefire-providers/surefire-junit47/pom.xml b/surefire-providers/surefire-junit47/pom.xml
index 39f68f1..aa91468 100644
--- a/surefire-providers/surefire-junit47/pom.xml
+++ b/surefire-providers/surefire-junit47/pom.xml
@@ -90,7 +90,7 @@
</execution>
<execution>
<id>test</id>
- <phase>process-sources</phase>
+ <phase>process-test-sources</phase>
<goals>
<goal>copy</goal>
</goals>
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
index 89c6104..f212415 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
@@ -25,6 +25,7 @@ import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.testset.TestSetFailedException;
@@ -118,6 +119,11 @@ public abstract class ConcurrentRunListener
reporterManagerThreadLocal.get().testExecutionSkippedByUser();
}
+ public RunMode markAs( RunMode currentRunMode )
+ {
+ return reporterManagerThreadLocal.get().markAs( currentRunMode );
+ }
+
public void testAssumptionFailure( ReportEntry failure )
{
final TestMethod testMethod = getOrCreateThreadAttachedTestMethod( failure );
@@ -196,18 +202,18 @@ public abstract class ConcurrentRunListener
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public void writeTestOutput( String output, boolean stdout )
{
TestMethod threadTestMethod = getThreadTestMethod();
if ( threadTestMethod != null )
{
LogicalStream logicalStream = threadTestMethod.getLogicalStream();
- logicalStream.write( stdout, buf, off, len );
+ logicalStream.write( stdout, output );
}
else
{
// Not able to associate output with any thread. Just dump to console
- consoleStream.println( buf, off, len );
+ consoleStream.println( output );
}
}
}
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java
index 2abfa58..656d55b 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreWrapper.java
@@ -140,7 +140,7 @@ final class JUnitCoreWrapper
if ( computer instanceof ParallelComputer )
{
String timeoutMessage = ( (ParallelComputer) computer ).describeElapsedTimeout();
- if ( timeoutMessage.length() != 0 )
+ if ( !timeoutMessage.isEmpty() )
{
throw new TestSetFailedException( timeoutMessage );
}
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/LogicalStream.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/LogicalStream.java
index 41e09b8..c79d53a 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/LogicalStream.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/LogicalStream.java
@@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
-import org.apache.maven.surefire.util.internal.ByteBuffer;
/**
* A stream-like object that preserves ordering between stdout/stderr
@@ -34,31 +33,24 @@ public final class LogicalStream
static final class Entry
{
- final boolean stdout;
+ private final boolean stdout;
+ private final String text;
- final byte[] b;
-
- final int off;
-
- final int len;
-
- Entry( boolean stdout, byte[] b, int off, int len )
+ Entry( boolean stdout, String text )
{
this.stdout = stdout;
- this.b = ByteBuffer.copy( b, off, len );
- this.off = 0;
- this.len = len;
+ this.text = text;
}
public void writeDetails( ConsoleOutputReceiver outputReceiver )
{
- outputReceiver.writeTestOutput( b, off, len, stdout );
+ outputReceiver.writeTestOutput( text, stdout );
}
@Override
public String toString()
{
- return new String( b, off, len );
+ return text;
}
public boolean isBlankLine()
@@ -67,9 +59,9 @@ public final class LogicalStream
}
}
- public synchronized void write( boolean stdout, byte b[], int off, int len )
+ public synchronized void write( boolean stdout, String text )
{
- Entry entry = new Entry( stdout, b, off, len );
+ Entry entry = new Entry( stdout, text );
if ( !entry.isBlankLine() )
{
output.add( entry );
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
index 539fd73..633385e 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
@@ -47,10 +47,10 @@ public class NonConcurrentRunListener
super( reporter );
}
- public synchronized void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public synchronized void writeTestOutput( String output, boolean stdout )
{
// We can write immediately: no parallelism and a single class.
- ( (ConsoleOutputReceiver) reporter ).writeTestOutput( buf, off, len, stdout );
+ ( (ConsoleOutputReceiver) reporter ).writeTestOutput( output, stdout );
}
protected SimpleReportEntry createReportEntry( Description description )
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestMethod.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestMethod.java
index eb388c6..b24833a 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestMethod.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestMethod.java
@@ -172,9 +172,9 @@ class TestMethod
return ls;
}
- public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
+ public void writeTestOutput( String output, boolean stdout )
{
- getLogicalStream().write( stdout, buf, off, len );
+ getLogicalStream().write( stdout, output );
}
public TestSet getTestSet()
diff --git a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/GroupMatcherMethodSelector.java b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/GroupMatcherMethodSelector.java
index db3bb41..9ff5fb4 100644
--- a/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/GroupMatcherMethodSelector.java
+++ b/surefire-providers/surefire-testng-utils/src/main/java/org/apache/maven/surefire/testng/utils/GroupMatcherMethodSelector.java
@@ -19,19 +19,21 @@ package org.apache.maven.surefire.testng.utils;
* under the License.
*/
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import org.apache.maven.surefire.group.match.AndGroupMatcher;
import org.apache.maven.surefire.group.match.GroupMatcher;
import org.apache.maven.surefire.group.match.InverseGroupMatcher;
import org.apache.maven.surefire.group.parse.GroupMatcherParser;
import org.apache.maven.surefire.group.parse.ParseException;
-
import org.testng.IMethodSelector;
import org.testng.IMethodSelectorContext;
import org.testng.ITestNGMethod;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
+
/**
* Method selector delegating to {@link GroupMatcher} to decide if a method is included or not.
*
@@ -77,7 +79,7 @@ public class GroupMatcherMethodSelector
{
AndGroupMatcher matcher = new AndGroupMatcher();
GroupMatcher in = null;
- if ( groups != null && groups.trim().length() > 0 )
+ if ( isNotBlank( groups ) )
{
in = new GroupMatcherParser( groups ).parse();
}
@@ -88,7 +90,7 @@ public class GroupMatcherMethodSelector
}
GroupMatcher ex = null;
- if ( excludedGroups != null && excludedGroups.trim().length() > 0 )
+ if ( isNotBlank( excludedGroups ) )
{
ex = new GroupMatcherParser( excludedGroups ).parse();
}