You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2020/09/26 21:07:01 UTC
[maven-surefire] branch base64 updated (e2db7c9 -> e192741)
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a change to branch base64
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.
discard e2db7c9 fixed Surefire224WellFormedXmlFailuresIT which makes sense
discard 7c3472f More realistic E2ETest. This test changed the performance result only in 10%.
discard d548e8c fixed the build and old tests
omit 1a7d822 employed the field "disabled"
omit 6b5b7aa removed unnecessary CharsetDecoder.decode() and improved the performance in 15%, added performance tests
omit b9f8708 committed the remaining classes
omit 6c2108a fixed the remaining tests
omit c35894a fixed the encoder
omit 520bd6c fixed method readInt() and tests
omit f024911 fixed old unit tests
omit d980e61 unit test for mapRunModes()
omit df09c2a unit tests for toEvent()
omit 26b4f6e unit tests for nextSegmentType()
omit e398381 unit tests for readCharset
omit f32044c unit tests: shouldReadNullString, shouldReadSingleCharString, shouldReadThreeCharactersString
omit 8d50c45 unit tests: shouldReadEventType, shouldEventTypeReachedEndOfStream
omit 5c9524d unit tests cleanup and employed default and non-default charset in the algorithm
omit d285d48 fixed typo DELIMITER_LENGTH, and introduced local variables
omit a7fede2 the main work in this class is done
omit 390cf0b 300 - 400 nanos per decoding std-out (100 chars/line)
add 968eb37 update ASF CI url
add a966b78 update ASF CI url
add 5b09e94 [SUREFIRE-756] Allow ability to capture executed random runOrder for re-play purposes
add 8a7b2e6 [SUREFIRE-1842] - NPE at end of successful test run
add 95b463a Revert "[SUREFIRE-1842] - NPE at end of successful test run"
add aef6573 [SUREFIRE-1842] - NPE at end of successful test run
add 847e950 JaCoCo version 0.8.6
add 51e0441 [SUREFIRE-1843] - Trademarks / privacy policy footer displays broken
add 3517103 Merge pull request #315 from michaelboyles/fix-footer
add 32bd56b [SUREFIRE-1845] Fixed the performance of Utf8RecodingDeferredFileOutputStream as a bottleneck for the tests with logs
new e192741 [SUREFIRE-1846] Remove Base64 in the Encoder/Decoder and gain the performance for the communication flow: Fork to Plugin
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (e2db7c9)
\
N -- N -- N refs/heads/base64 (e192741)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
README.md | 10 +-
.../maven/plugin/failsafe/IntegrationTestMojo.java | 28 ++++
.../plugin/surefire/AbstractSurefireMojo.java | 18 ++-
.../surefire/booterclient/BooterSerializer.java | 2 +
.../output/ThreadedStreamConsumer.java | 2 +
.../surefire/report/StatelessXmlReporter.java | 1 -
.../Utf8RecodingDeferredFileOutputStream.java | 151 +++++++++++++++++----
.../AbstractSurefireMojoJava7PlusTest.java | 12 ++
.../plugin/surefire/AbstractSurefireMojoTest.java | 12 ++
.../maven/plugin/surefire/MojoMocklessTest.java | 12 ++
.../surefire/report/StatelessXmlReporterTest.java | 142 ++++++++++++++++++-
.../maven/plugin/surefire/SurefirePlugin.java | 28 ++++
pom.xml | 4 +-
src/site/site.xml | 7 +-
.../surefire/api/booter/BaseProviderFactory.java | 3 +-
.../surefire/api/testset/RunOrderParameters.java | 28 ++++
.../api/util/DefaultRunOrderCalculator.java | 12 +-
.../maven/surefire/booter/BooterConstants.java | 1 +
.../maven/surefire/booter/BooterDeserializer.java | 4 +-
.../maven/surefire/booter/SurefireReflector.java | 5 +-
.../surefire/booter/SurefireReflectorTest.java | 24 +++-
.../org/apache/maven/surefire/its/RunOrderIT.java | 49 +++++++
.../surefire/its/fixture/OutputValidator.java | 27 ++++
.../surefire/its/fixture/SurefireLauncher.java | 6 +
.../maven/surefire/junit4/JUnit4ProviderTest.java | 3 +
25 files changed, 539 insertions(+), 52 deletions(-)
[maven-surefire] 01/01: [SUREFIRE-1846] Remove Base64 in the
Encoder/Decoder and gain the performance for the communication flow: Fork
to Plugin
Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch base64
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit e1927414221e75a1e1a2359fea3634d4b13bb8b1
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Aug 1 23:09:34 2020 +0200
[SUREFIRE-1846] Remove Base64 in the Encoder/Decoder and gain the performance for the communication flow: Fork to Plugin
---
.../plugin/surefire/booterclient/ForkStarter.java | 8 +
.../surefire/extensions/EventConsumerThread.java | 1002 ++++++++++----
.../booterclient/ForkingRunListenerTest.java | 27 +-
.../plugin/surefire/booterclient/MainClass.java | 2 +-
.../booterclient/output/ForkClientTest.java | 33 +-
.../output/ThreadedStreamConsumerTest.java | 2 +-
.../maven/plugin/surefire/extensions/E2ETest.java | 133 +-
.../extensions/EventConsumerThreadTest.java | 1237 +++++++++++++++++
.../extensions/ForkedProcessEventNotifierTest.java | 156 +--
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 2 +
.../maven/surefire/extensions/ForkChannelTest.java | 18 +-
.../maven/surefire/api/booter/Constants.java | 51 +-
.../api/booter/ForkedProcessEventType.java | 260 +++-
.../apache/maven/surefire/api/report/RunMode.java | 28 +-
.../spi/LegacyMasterProcessChannelDecoder.java | 2 +-
.../spi/LegacyMasterProcessChannelEncoder.java | 357 +++--
.../spi/LegacyMasterProcessChannelEncoderTest.java | 1412 ++++++++++++--------
.../surefire/extensions/ForkNodeArguments.java | 3 +
.../jiras/Surefire224WellFormedXmlFailuresIT.java | 2 +-
.../java/wellFormedXmlFailures/TestSurefire3.java | 2 +-
20 files changed, 3547 insertions(+), 1190 deletions(-)
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 0a333f6..1ac3917 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
@@ -912,6 +912,14 @@ public class ForkStarter
return InPluginProcessDumpSingleton.getSingleton().dumpStreamText( text, dumpLogDir, forkChannelId );
}
+ @Nonnull
+ @Override
+ public File dumpStreamException( @Nonnull Throwable t )
+ {
+ return InPluginProcessDumpSingleton.getSingleton()
+ .dumpStreamException( t, t.getLocalizedMessage(), dumpLogDir, forkChannelId );
+ }
+
@Override
public void logWarningAtEnd( @Nonnull String text )
{
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
index 1d5686b..2647b60 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
@@ -44,30 +44,41 @@ import org.apache.maven.surefire.api.event.TestStartingEvent;
import org.apache.maven.surefire.api.event.TestSucceededEvent;
import org.apache.maven.surefire.api.event.TestsetCompletedEvent;
import org.apache.maven.surefire.api.event.TestsetStartingEvent;
+import org.apache.maven.surefire.api.report.RunMode;
+import org.apache.maven.surefire.api.report.StackTraceWriter;
+import org.apache.maven.surefire.api.report.TestSetReportEntry;
import org.apache.maven.surefire.extensions.CloseableDaemonThread;
import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.extensions.ForkNodeArguments;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
-import org.apache.maven.surefire.api.report.RunMode;
-import org.apache.maven.surefire.api.report.StackTraceWriter;
-import org.apache.maven.surefire.api.report.TestSetReportEntry;
-import org.apache.maven.surefire.shared.codec.binary.Base64;
+import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
+import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
-import java.util.Iterator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+import static java.nio.charset.CodingErrorAction.REPLACE;
import static java.nio.charset.StandardCharsets.US_ASCII;
-import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.MAGIC_NUMBER;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.StreamReadStatus.OVERFLOW;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.StreamReadStatus.UNDERFLOW;
+import static org.apache.maven.surefire.api.booter.Constants.DEFAULT_STREAM_ENCODING;
+import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER_BYTES;
import static org.apache.maven.surefire.api.report.CategorizedReportEntry.reportEntry;
-import static org.apache.maven.surefire.api.report.RunMode.MODES;
/**
*
@@ -82,8 +93,64 @@ public class EventConsumerThread extends CloseableDaemonThread
"could not reserve enough space", "could not allocate", "unable to allocate", // memory errors
"java.lang.module.findexception" // JPMS errors
};
+
private static final String PRINTABLE_JVM_NATIVE_STREAM = "Listening for transport dt_socket at address:";
- private static final Base64 BASE64 = new Base64();
+
+ private static final SegmentType[] EVENT_WITHOUT_DATA = new SegmentType[] {
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final SegmentType[] EVENT_WITH_ERROR_TRACE = new SegmentType[] {
+ SegmentType.STRING_ENCODING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final SegmentType[] EVENT_WITH_ONE_STRING = new SegmentType[] {
+ SegmentType.STRING_ENCODING,
+ SegmentType.DATA_STRING,
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final SegmentType[] EVENT_WITH_RUNMODE_AND_ONE_STRING = new SegmentType[] {
+ SegmentType.RUN_MODE,
+ SegmentType.STRING_ENCODING,
+ SegmentType.DATA_STRING,
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final SegmentType[] EVENT_WITH_RUNMODE_AND_TWO_STRINGS = new SegmentType[] {
+ SegmentType.RUN_MODE,
+ SegmentType.STRING_ENCODING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final SegmentType[] EVENT_TEST_CONTROL = new SegmentType[] {
+ SegmentType.RUN_MODE,
+ SegmentType.STRING_ENCODING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_INT,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.DATA_STRING,
+ SegmentType.END_OF_FRAME
+ };
+
+ private static final int BUFFER_SIZE = 1024;
+ private static final byte[] DEFAULT_STREAM_ENCODING_BYTES = DEFAULT_STREAM_ENCODING.name().getBytes( US_ASCII );
+ private static final int DELIMITER_LENGTH = 1;
+ private static final int BYTE_LENGTH = 1;
+ private static final int INT_LENGTH = 4;
+ private static final int NO_POSITION = -1;
private final ReadableByteChannel channel;
private final EventHandler<Event> eventHandler;
@@ -133,371 +200,778 @@ public class EventConsumerThread extends CloseableDaemonThread
@SuppressWarnings( "checkstyle:innerassignment" )
private void decode() throws IOException
{
- List<String> tokens = new ArrayList<>();
- StringBuilder line = new StringBuilder();
- StringBuilder token = new StringBuilder( MAGIC_NUMBER.length() );
- ByteBuffer buffer = ByteBuffer.allocate( 1024 );
- buffer.position( buffer.limit() );
- boolean streamContinues;
+ Map<Segment, ForkedProcessEventType> eventTypes = mapEventTypes();
+ Map<Segment, RunMode> runModes = mapRunModes();
+ Memento memento = new Memento();
+ memento.bb.limit( 0 );
- start:
do
{
- line.setLength( 0 );
- tokens.clear();
- token.setLength( 0 );
- FrameCompletion completion = null;
- for ( boolean frameStarted = false; streamContinues = read( buffer ); completion = null )
+ try
{
- char c = (char) buffer.get();
-
- if ( c == '\n' || c == '\r' )
+ ForkedProcessEventType eventType = readEventType( eventTypes, memento );
+ if ( eventType == null )
{
- printExistingLine( line );
- continue start;
+ throw new MalformedFrameException( memento.line.positionByteBuffer, memento.bb.position() );
}
-
- line.append( c );
-
- if ( !frameStarted )
+ RunMode runMode = null;
+ for ( SegmentType segmentType : nextSegmentType( eventType ) )
{
- if ( c == ':' )
+ if ( segmentType == null )
{
- frameStarted = true;
- token.setLength( 0 );
- tokens.clear();
+ break;
}
- }
- else
- {
- if ( c == ':' )
+
+ switch ( segmentType )
{
- tokens.add( token.toString() );
- token.setLength( 0 );
- completion = frameCompleteness( tokens );
- if ( completion == FrameCompletion.COMPLETE )
- {
- line.setLength( 0 );
+ case RUN_MODE:
+ runMode = runModes.get( readSegment( memento ) );
break;
- }
- else if ( completion == FrameCompletion.MALFORMED )
- {
- printExistingLine( line );
- continue start;
- }
- }
- else
- {
- token.append( c );
+ case STRING_ENCODING:
+ memento.setCharset( readCharset( memento ) );
+ break;
+ case DATA_STRING:
+ memento.data.add( readString( memento ) );
+ break;
+ case DATA_INT:
+ memento.data.add( readInteger( memento ) );
+ break;
+ case END_OF_FRAME:
+ memento.line.positionByteBuffer = memento.bb.position();
+ if ( !disabled )
+ {
+ eventHandler.handleEvent( toEvent( eventType, runMode, memento.data ) );
+ }
+ break;
+ default:
+ memento.line.positionByteBuffer = NO_POSITION;
+ arguments.dumpStreamText( "Unknown enum ("
+ + ForkedProcessEventType.class.getSimpleName()
+ + ") "
+ + segmentType );
}
}
}
-
- if ( completion == FrameCompletion.COMPLETE )
+ catch ( MalformedFrameException e )
{
- Event event = toEvent( tokens );
- if ( !disabled && event != null )
+ if ( e.hasValidPositions() )
{
- eventHandler.handleEvent( event );
+ int length = e.readTo - e.readFrom;
+ memento.line.write( memento.bb, e.readFrom, length );
}
}
-
- if ( !streamContinues )
+ catch ( RuntimeException e )
{
- printExistingLine( line );
- return;
+ arguments.dumpStreamException( e );
+ }
+ catch ( IOException e )
+ {
+ printRemainingStream( memento );
+ throw e;
+ }
+ finally
+ {
+ memento.reset();
}
}
while ( true );
}
- private boolean read( ByteBuffer buffer ) throws IOException
+ protected ForkedProcessEventType readEventType( Map<Segment, ForkedProcessEventType> eventTypes, Memento memento )
+ throws IOException, MalformedFrameException
{
- if ( buffer.hasRemaining() && buffer.position() > 0 )
+ int readCount = DELIMITER_LENGTH + MAGIC_NUMBER_BYTES.length + DELIMITER_LENGTH
+ + BYTE_LENGTH + DELIMITER_LENGTH;
+ read( memento, readCount );
+ checkHeader( memento );
+ return eventTypes.get( readSegment( memento ) );
+ }
+
+ protected String readString( Memento memento ) throws IOException, MalformedFrameException
+ {
+ memento.cb.clear();
+ int readCount = readInt( memento );
+ read( memento, readCount + DELIMITER_LENGTH );
+
+ final String string;
+ if ( readCount == 0 )
{
- return true;
+ string = "";
+ }
+ else if ( readCount == 1 )
+ {
+ read( memento, 1 );
+ byte oneChar = memento.bb.get();
+ string = oneChar == 0 ? null : String.valueOf( (char) oneChar );
}
else
{
- buffer.clear();
- boolean isEndOfStream = channel.read( buffer ) == -1;
- buffer.flip();
- return !isEndOfStream;
+ string = readString( memento, readCount );
}
+
+ checkDelimiter( memento );
+ return string;
}
- private void printExistingLine( StringBuilder line )
+ @Nonnull
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ protected Segment readSegment( Memento memento ) throws IOException, MalformedFrameException
{
- if ( line.length() != 0 )
+ int readCount = readByte( memento ) & 0xff;
+ read( memento, readCount + DELIMITER_LENGTH );
+ ByteBuffer bb = memento.bb;
+ Segment segment = new Segment( bb.array(), bb.arrayOffset() + bb.position(), readCount );
+ bb.position( bb.position() + readCount );
+ checkDelimiter( memento );
+ return segment;
+ }
+
+ @Nonnull
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ protected Charset readCharset( Memento memento ) throws IOException, MalformedFrameException
+ {
+ int length = readByte( memento ) & 0xff;
+ read( memento, length + DELIMITER_LENGTH );
+ ByteBuffer bb = memento.bb;
+ byte[] array = bb.array();
+ int offset = bb.arrayOffset() + bb.position();
+ bb.position( bb.position() + length );
+ boolean isDefaultEncoding = false;
+ if ( length == DEFAULT_STREAM_ENCODING_BYTES.length )
{
- ConsoleLogger logger = arguments.getConsoleLogger();
- String s = line.toString().trim();
- if ( s.contains( PRINTABLE_JVM_NATIVE_STREAM ) )
+ isDefaultEncoding = true;
+ for ( int i = 0; i < length; i++ )
{
- if ( logger.isDebugEnabled() )
- {
- logger.debug( s );
- }
- else if ( logger.isInfoEnabled() )
- {
- logger.info( s );
- }
- else
- {
- // In case of debugging forked JVM, see PRINTABLE_JVM_NATIVE_STREAM.
- System.out.println( s );
- }
+ isDefaultEncoding &= DEFAULT_STREAM_ENCODING_BYTES[i] == array[offset + i];
}
- else
- {
- if ( isJvmError( s ) )
- {
- logger.error( s );
- }
- String msg = "Corrupted STDOUT by directly writing to native stream in forked JVM "
- + arguments.getForkChannelId() + ".";
- File dumpFile = arguments.dumpStreamText( msg + " Stream '" + s + "'." );
- arguments.logWarningAtEnd( msg + " See FAQ web page and the dump file " + dumpFile.getAbsolutePath() );
+ }
- if ( logger.isDebugEnabled() )
+ try
+ {
+ Charset charset =
+ isDefaultEncoding
+ ? DEFAULT_STREAM_ENCODING
+ : Charset.forName( new String( array, offset, length, US_ASCII ) );
+
+ checkDelimiter( memento );
+ return charset;
+ }
+ catch ( IllegalArgumentException e )
+ {
+ throw new MalformedFrameException( memento.line.positionByteBuffer, bb.position() );
+ }
+ }
+
+ private static void checkHeader( Memento memento ) throws MalformedFrameException
+ {
+ ByteBuffer bb = memento.bb;
+
+ checkDelimiter( memento );
+
+ int shift = 0;
+ try
+ {
+ for ( int start = bb.arrayOffset() + bb.position(), length = MAGIC_NUMBER_BYTES.length;
+ shift < length; shift++ )
+ {
+ if ( bb.array()[shift + start] != MAGIC_NUMBER_BYTES[shift] )
{
- logger.debug( s );
+ throw new MalformedFrameException( memento.line.positionByteBuffer, bb.position() + shift );
}
}
}
+ finally
+ {
+ bb.position( bb.position() + shift );
+ }
+
+ checkDelimiter( memento );
}
- private Event toEvent( List<String> tokensInFrame )
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ private static void checkDelimiter( Memento memento ) throws MalformedFrameException
{
- Iterator<String> tokens = tokensInFrame.iterator();
- String header = tokens.next();
- assert header != null;
-
- ForkedProcessEventType event = ForkedProcessEventType.byOpcode( tokens.next() );
+ ByteBuffer bb = memento.bb;
+ if ( ( 0xff & bb.get() ) != ':' )
+ {
+ throw new MalformedFrameException( memento.line.positionByteBuffer, bb.position() );
+ }
+ }
- if ( event == null )
+ static SegmentType[] nextSegmentType( ForkedProcessEventType eventType )
+ {
+ switch ( eventType )
{
- return null;
+ case BOOTERCODE_BYE:
+ case BOOTERCODE_STOP_ON_NEXT_TEST:
+ case BOOTERCODE_NEXT_TEST:
+ return EVENT_WITHOUT_DATA;
+ case BOOTERCODE_CONSOLE_ERROR:
+ case BOOTERCODE_JVM_EXIT_ERROR:
+ return EVENT_WITH_ERROR_TRACE;
+ case BOOTERCODE_CONSOLE_INFO:
+ case BOOTERCODE_CONSOLE_DEBUG:
+ case BOOTERCODE_CONSOLE_WARNING:
+ return EVENT_WITH_ONE_STRING;
+ case BOOTERCODE_STDOUT:
+ case BOOTERCODE_STDOUT_NEW_LINE:
+ case BOOTERCODE_STDERR:
+ case BOOTERCODE_STDERR_NEW_LINE:
+ return EVENT_WITH_RUNMODE_AND_ONE_STRING;
+ case BOOTERCODE_SYSPROPS:
+ return EVENT_WITH_RUNMODE_AND_TWO_STRINGS;
+ case BOOTERCODE_TESTSET_STARTING:
+ case BOOTERCODE_TESTSET_COMPLETED:
+ case BOOTERCODE_TEST_STARTING:
+ case BOOTERCODE_TEST_SUCCEEDED:
+ case BOOTERCODE_TEST_FAILED:
+ case BOOTERCODE_TEST_SKIPPED:
+ case BOOTERCODE_TEST_ERROR:
+ case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
+ return EVENT_TEST_CONTROL;
+ default:
+ throw new IllegalArgumentException( "Unknown enum " + eventType );
}
+ }
- if ( event.isControlCategory() )
+ protected StreamReadStatus read( Memento memento, int recommendedCount ) throws IOException
+ {
+ ByteBuffer buffer = memento.bb;
+ if ( buffer.remaining() >= recommendedCount && buffer.position() != 0 )
+ {
+ return OVERFLOW;
+ }
+ else
{
- switch ( event )
+ if ( buffer.position() != 0 && recommendedCount > buffer.capacity() - buffer.position() )
+ {
+ buffer.compact().flip();
+ memento.line.positionByteBuffer = 0;
+ }
+ int mark = buffer.position();
+ buffer.position( buffer.limit() );
+ buffer.limit( buffer.capacity() );
+ boolean isEnd = false;
+ while ( !isEnd && buffer.position() - mark < recommendedCount && buffer.position() != buffer.limit() )
+ {
+ isEnd = channel.read( buffer ) == -1;
+ }
+
+ buffer.limit( buffer.position() );
+ buffer.position( mark );
+ int readBytes = buffer.remaining();
+
+ if ( isEnd && readBytes < recommendedCount )
+ {
+ throw new EOFException();
+ }
+ else
{
- case BOOTERCODE_BYE:
- return new ControlByeEvent();
- case BOOTERCODE_STOP_ON_NEXT_TEST:
- return new ControlStopOnNextTestEvent();
- case BOOTERCODE_NEXT_TEST:
- return new ControlNextTestEvent();
- default:
- throw new IllegalStateException( "Unknown enum " + event );
+ return readBytes >= recommendedCount ? OVERFLOW : UNDERFLOW;
}
}
- else if ( event.isConsoleErrorCategory() || event.isJvmExitError() )
+ }
+
+ static Event toEvent( ForkedProcessEventType eventType, RunMode runMode, List<Object> args )
+ {
+ switch ( eventType )
{
- Charset encoding = Charset.forName( tokens.next() );
- StackTraceWriter stackTraceWriter = decodeTrace( encoding, tokens.next(), tokens.next(), tokens.next() );
- return event.isConsoleErrorCategory()
- ? new ConsoleErrorEvent( stackTraceWriter )
- : new JvmExitErrorEvent( stackTraceWriter );
+ case BOOTERCODE_BYE:
+ return new ControlByeEvent();
+ case BOOTERCODE_STOP_ON_NEXT_TEST:
+ return new ControlStopOnNextTestEvent();
+ case BOOTERCODE_NEXT_TEST:
+ return new ControlNextTestEvent();
+ case BOOTERCODE_CONSOLE_ERROR:
+ return new ConsoleErrorEvent( toStackTraceWriter( args ) );
+ case BOOTERCODE_JVM_EXIT_ERROR:
+ return new JvmExitErrorEvent( toStackTraceWriter( args ) );
+ case BOOTERCODE_CONSOLE_INFO:
+ return new ConsoleInfoEvent( (String) args.get( 0 ) );
+ case BOOTERCODE_CONSOLE_DEBUG:
+ return new ConsoleDebugEvent( (String) args.get( 0 ) );
+ case BOOTERCODE_CONSOLE_WARNING:
+ return new ConsoleWarningEvent( (String) args.get( 0 ) );
+ case BOOTERCODE_STDOUT:
+ return new StandardStreamOutEvent( runMode, (String) args.get( 0 ) );
+ case BOOTERCODE_STDOUT_NEW_LINE:
+ return new StandardStreamOutWithNewLineEvent( runMode, (String) args.get( 0 ) );
+ case BOOTERCODE_STDERR:
+ return new StandardStreamErrEvent( runMode, (String) args.get( 0 ) );
+ case BOOTERCODE_STDERR_NEW_LINE:
+ return new StandardStreamErrWithNewLineEvent( runMode, (String) args.get( 0 ) );
+ case BOOTERCODE_SYSPROPS:
+ String key = (String) args.get( 0 );
+ String value = (String) args.get( 1 );
+ return new SystemPropertyEvent( runMode, key, value );
+ case BOOTERCODE_TESTSET_STARTING:
+ return new TestsetStartingEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TESTSET_COMPLETED:
+ return new TestsetCompletedEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_STARTING:
+ return new TestStartingEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_SUCCEEDED:
+ return new TestSucceededEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_FAILED:
+ return new TestFailedEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_SKIPPED:
+ return new TestSkippedEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_ERROR:
+ return new TestErrorEvent( runMode, toReportEntry( args ) );
+ case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
+ return new TestAssumptionFailureEvent( runMode, toReportEntry( args ) );
+ default:
+ throw new IllegalArgumentException( "Missing a branch for the event type " + eventType );
}
- else if ( event.isConsoleCategory() )
+ }
+
+ private static void printCorruptedStream( Memento memento )
+ {
+ ByteBuffer bb = memento.bb;
+ if ( bb.hasRemaining() )
{
- Charset encoding = Charset.forName( tokens.next() );
- String msg = decode( tokens.next(), encoding );
- switch ( event )
- {
- case BOOTERCODE_CONSOLE_INFO:
- return new ConsoleInfoEvent( msg );
- case BOOTERCODE_CONSOLE_DEBUG:
- return new ConsoleDebugEvent( msg );
- case BOOTERCODE_CONSOLE_WARNING:
- return new ConsoleWarningEvent( msg );
- default:
- throw new IllegalStateException( "Unknown enum " + event );
- }
+ int bytesToWrite = bb.remaining();
+ memento.line.write( bb, bb.position(), bytesToWrite );
+ bb.position( bb.position() + bytesToWrite );
}
- else if ( event.isStandardStreamCategory() )
+ }
+
+ /**
+ * Print the last string which has not been finished by a new line character.
+ *
+ * @param memento current memento object
+ */
+ private static void printRemainingStream( Memento memento )
+ {
+ printCorruptedStream( memento );
+ memento.line.printExistingLine();
+ memento.line.count = 0;
+ }
+
+ @Nonnull
+ private static TestSetReportEntry toReportEntry( List<Object> args )
+ {
+ // ReportEntry:
+ String source = (String) args.get( 0 );
+ String sourceText = (String) args.get( 1 );
+ String name = (String) args.get( 2 );
+ String nameText = (String) args.get( 3 );
+ String group = (String) args.get( 4 );
+ String message = (String) args.get( 5 );
+ Integer timeElapsed = (Integer) args.get( 6 );
+ // StackTraceWriter:
+ String traceMessage = (String) args.get( 7 );
+ String smartTrimmedStackTrace = (String) args.get( 8 );
+ String stackTrace = (String) args.get( 9 );
+ return newReportEntry( source, sourceText, name, nameText, group, message, timeElapsed,
+ traceMessage, smartTrimmedStackTrace, stackTrace );
+ }
+
+ private static StackTraceWriter toStackTraceWriter( List<Object> args )
+ {
+ String traceMessage = (String) args.get( 0 );
+ String smartTrimmedStackTrace = (String) args.get( 1 );
+ String stackTrace = (String) args.get( 2 );
+ return toTrace( traceMessage, smartTrimmedStackTrace, stackTrace );
+ }
+
+ private static StackTraceWriter toTrace( String traceMessage, String smartTrimmedStackTrace, String stackTrace )
+ {
+ boolean exists = traceMessage != null || stackTrace != null || smartTrimmedStackTrace != null;
+ return exists ? new DeserializedStacktraceWriter( traceMessage, smartTrimmedStackTrace, stackTrace ) : null;
+ }
+
+ static TestSetReportEntry newReportEntry( // ReportEntry:
+ String source, String sourceText, String name,
+ String nameText, String group, String message,
+ Integer timeElapsed,
+ // StackTraceWriter:
+ String traceMessage,
+ String smartTrimmedStackTrace, String stackTrace )
+ throws NumberFormatException
+ {
+ StackTraceWriter stackTraceWriter = toTrace( traceMessage, smartTrimmedStackTrace, stackTrace );
+ return reportEntry( source, sourceText, name, nameText, group, stackTraceWriter, timeElapsed, message,
+ Collections.<String, String>emptyMap() );
+ }
+
+ private static boolean isJvmError( String line )
+ {
+ String lineLower = line.toLowerCase();
+ for ( String errorPattern : JVM_ERROR_PATTERNS )
{
- RunMode mode = MODES.get( tokens.next() );
- Charset encoding = Charset.forName( tokens.next() );
- String output = decode( tokens.next(), encoding );
- switch ( event )
+ if ( lineLower.contains( errorPattern ) )
{
- case BOOTERCODE_STDOUT:
- return new StandardStreamOutEvent( mode, output );
- case BOOTERCODE_STDOUT_NEW_LINE:
- return new StandardStreamOutWithNewLineEvent( mode, output );
- case BOOTERCODE_STDERR:
- return new StandardStreamErrEvent( mode, output );
- case BOOTERCODE_STDERR_NEW_LINE:
- return new StandardStreamErrWithNewLineEvent( mode, output );
- default:
- throw new IllegalStateException( "Unknown enum " + event );
+ return true;
}
}
- else if ( event.isSysPropCategory() )
+ return false;
+ }
+
+ private static int decodeString( @Nonnull CharsetDecoder decoder, @Nonnull ByteBuffer input,
+ @Nonnull CharBuffer output, @Nonnegative int bytesToDecode,
+ boolean endOfInput, @Nonnegative int errorStreamFrom )
+ throws MalformedFrameException
+ {
+ int limit = input.limit();
+ input.limit( input.position() + bytesToDecode );
+
+ CoderResult result = decoder.decode( input, output, endOfInput );
+ if ( result.isError() || result.isMalformed() )
{
- RunMode mode = MODES.get( tokens.next() );
- Charset encoding = Charset.forName( tokens.next() );
- String key = decode( tokens.next(), encoding );
- String value = decode( tokens.next(), encoding );
- return new SystemPropertyEvent( mode, key, value );
+ throw new MalformedFrameException( errorStreamFrom, input.position() );
}
- else if ( event.isTestCategory() )
+
+ int decodedBytes = bytesToDecode - input.remaining();
+ input.limit( limit );
+ return decodedBytes;
+ }
+
+ String readString( @Nonnull final Memento memento, @Nonnegative final int totalBytes )
+ throws IOException, MalformedFrameException
+ {
+ memento.getDecoder().reset();
+ final CharBuffer output = memento.cb;
+ output.clear();
+ final ByteBuffer input = memento.bb;
+ final List<String> strings = new ArrayList<>();
+ int countDecodedBytes = 0;
+ for ( boolean endOfInput = false; !endOfInput; )
{
- RunMode mode = MODES.get( tokens.next() );
- Charset encoding = Charset.forName( tokens.next() );
- TestSetReportEntry reportEntry =
- decodeReportEntry( encoding, tokens.next(), tokens.next(), tokens.next(), tokens.next(),
- tokens.next(), tokens.next(), tokens.next(), tokens.next(), tokens.next(), tokens.next() );
+ final int bytesToRead = totalBytes - countDecodedBytes;
+ read( memento, bytesToRead - input.remaining() );
+ int bytesToDecode = min( input.remaining(), bytesToRead );
+ final boolean isLastChunk = bytesToDecode == bytesToRead;
+ endOfInput = countDecodedBytes + bytesToDecode >= totalBytes;
+ do
+ {
+ boolean endOfChunk = output.remaining() >= bytesToRead;
+ boolean endOfOutput = isLastChunk && endOfChunk;
+ int readInputBytes = decodeString( memento.getDecoder(), input, output, bytesToDecode, endOfOutput,
+ memento.line.positionByteBuffer );
+ bytesToDecode -= readInputBytes;
+ countDecodedBytes += readInputBytes;
+ }
+ while ( isLastChunk && bytesToDecode > 0 && output.hasRemaining() );
- switch ( event )
+ if ( isLastChunk || !output.hasRemaining() )
{
- case BOOTERCODE_TESTSET_STARTING:
- return new TestsetStartingEvent( mode, reportEntry );
- case BOOTERCODE_TESTSET_COMPLETED:
- return new TestsetCompletedEvent( mode, reportEntry );
- case BOOTERCODE_TEST_STARTING:
- return new TestStartingEvent( mode, reportEntry );
- case BOOTERCODE_TEST_SUCCEEDED:
- return new TestSucceededEvent( mode, reportEntry );
- case BOOTERCODE_TEST_FAILED:
- return new TestFailedEvent( mode, reportEntry );
- case BOOTERCODE_TEST_SKIPPED:
- return new TestSkippedEvent( mode, reportEntry );
- case BOOTERCODE_TEST_ERROR:
- return new TestErrorEvent( mode, reportEntry );
- case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
- return new TestAssumptionFailureEvent( mode, reportEntry );
- default:
- throw new IllegalStateException( "Unknown enum " + event );
+ strings.add( output.flip().toString() );
+ output.clear();
}
}
- throw new IllegalStateException( "Missing a branch for the event type " + event );
+ memento.getDecoder().reset();
+ output.clear();
+
+ return toString( strings );
+ }
+
+ protected byte readByte( Memento memento ) throws IOException, MalformedFrameException
+ {
+ read( memento, BYTE_LENGTH + DELIMITER_LENGTH );
+ byte b = memento.bb.get();
+ checkDelimiter( memento );
+ return b;
+ }
+
+ protected int readInt( Memento memento ) throws IOException, MalformedFrameException
+ {
+ read( memento, INT_LENGTH + DELIMITER_LENGTH );
+ int i = memento.bb.getInt();
+ checkDelimiter( memento );
+ return i;
+ }
+
+ protected Integer readInteger( Memento memento ) throws IOException, MalformedFrameException
+ {
+ read( memento, BYTE_LENGTH );
+ boolean isNullObject = memento.bb.get() == 0;
+ if ( isNullObject )
+ {
+ read( memento, DELIMITER_LENGTH );
+ checkDelimiter( memento );
+ return null;
+ }
+ return readInt( memento );
+ }
+
+ private static String toString( List<String> strings )
+ {
+ if ( strings.size() == 1 )
+ {
+ return strings.get( 0 );
+ }
+ StringBuilder concatenated = new StringBuilder( strings.size() * BUFFER_SIZE );
+ for ( String s : strings )
+ {
+ concatenated.append( s );
+ }
+ return concatenated.toString();
+ }
+
+ static Map<Segment, ForkedProcessEventType> mapEventTypes()
+ {
+ Map<Segment, ForkedProcessEventType> map = new HashMap<>();
+ for ( ForkedProcessEventType e : ForkedProcessEventType.values() )
+ {
+ byte[] array = e.getOpcode().getBytes( US_ASCII );
+ map.put( new Segment( array, 0, array.length ), e );
+ }
+ return map;
+ }
+
+ static Map<Segment, RunMode> mapRunModes()
+ {
+ Map<Segment, RunMode> map = new HashMap<>();
+ for ( RunMode e : RunMode.values() )
+ {
+ byte[] array = e.geRunmode().getBytes( US_ASCII );
+ map.put( new Segment( array, 0, array.length ), e );
+ }
+ return map;
+ }
+
+ enum StreamReadStatus
+ {
+ UNDERFLOW,
+ OVERFLOW,
+ EOF
+ }
+
+ enum SegmentType
+ {
+ RUN_MODE,
+ STRING_ENCODING,
+ DATA_STRING,
+ DATA_INT,
+ END_OF_FRAME
}
- private static FrameCompletion frameCompleteness( List<String> tokens )
+ /**
+ * This class avoids locking which gains the performance of this decoder.
+ */
+ private class BufferedStream
{
- if ( !tokens.isEmpty() && !MAGIC_NUMBER.equals( tokens.get( 0 ) ) )
+ private byte[] buffer;
+ private int count;
+ private int positionByteBuffer;
+ private boolean isNewLine;
+
+ BufferedStream( int capacity )
{
- return FrameCompletion.MALFORMED;
+ this.buffer = new byte[capacity];
}
- if ( tokens.size() >= 2 )
+ void write( ByteBuffer bb, int position, int length )
{
- String opcode = tokens.get( 1 );
- ForkedProcessEventType event = ForkedProcessEventType.byOpcode( opcode );
- if ( event == null )
+ ensureCapacity( length );
+ byte[] array = bb.array();
+ int pos = bb.arrayOffset() + position;
+ while ( length-- > 0 )
{
- return FrameCompletion.MALFORMED;
+ positionByteBuffer++;
+ byte b = array[pos++];
+ if ( b == '\r' || b == '\n' )
+ {
+ if ( !isNewLine )
+ {
+ printExistingLine();
+ count = 0;
+ }
+ isNewLine = true;
+ }
+ else
+ {
+ buffer[count++] = b;
+ isNewLine = false;
+ }
}
- else if ( event.isControlCategory() )
+ }
+
+ private boolean isEmpty()
+ {
+ return count == 0;
+ }
+
+ @Override
+ public String toString()
+ {
+ return new String( buffer, 0, count, DEFAULT_STREAM_ENCODING );
+ }
+
+ private void ensureCapacity( int addCapacity )
+ {
+ int oldCapacity = buffer.length;
+ int exactCapacity = count + addCapacity;
+ if ( exactCapacity < 0 )
{
- return FrameCompletion.COMPLETE;
+ throw new OutOfMemoryError();
}
- else if ( event.isConsoleErrorCategory() )
+
+ if ( oldCapacity < exactCapacity )
{
- return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ int newCapacity = oldCapacity << 1;
+ buffer = Arrays.copyOf( buffer, max( newCapacity, exactCapacity ) );
}
- else if ( event.isConsoleCategory() )
+ }
+
+ void printExistingLine()
+ {
+ if ( isEmpty() )
{
- return tokens.size() == 4 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ return;
}
- else if ( event.isStandardStreamCategory() )
+ ConsoleLogger logger = arguments.getConsoleLogger();
+ String s = toString();
+ if ( s.contains( PRINTABLE_JVM_NATIVE_STREAM ) )
{
- return tokens.size() == 5 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( s );
+ }
+ else if ( logger.isInfoEnabled() )
+ {
+ logger.info( s );
+ }
+ else
+ {
+ // In case of debugging forked JVM, see PRINTABLE_JVM_NATIVE_STREAM.
+ System.out.println( s );
+ }
}
- else if ( event.isSysPropCategory() )
+ else
{
- return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ if ( isJvmError( s ) )
+ {
+ logger.error( s );
+ }
+ else if ( logger.isDebugEnabled() )
+ {
+ logger.debug( s );
+ }
+
+ String msg = "Corrupted STDOUT by directly writing to native stream in forked JVM "
+ + arguments.getForkChannelId() + ".";
+ File dumpFile = arguments.dumpStreamText( msg + " Stream '" + s + "'." );
+ arguments.logWarningAtEnd( msg + " See FAQ web page and the dump file " + dumpFile.getAbsolutePath() );
}
- else if ( event.isTestCategory() )
+ }
+ }
+
+ class Memento
+ {
+ private final CharsetDecoder defaultDecoder;
+ private CharsetDecoder currentDecoder;
+ final BufferedStream line = new BufferedStream( 32 );
+ final List<Object> data = new ArrayList<>();
+ final CharBuffer cb = CharBuffer.allocate( BUFFER_SIZE );
+ final ByteBuffer bb = ByteBuffer.allocate( BUFFER_SIZE );
+
+ Memento()
+ {
+ defaultDecoder = DEFAULT_STREAM_ENCODING.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ }
+
+ void reset()
+ {
+ currentDecoder = null;
+ data.clear();
+ }
+
+ CharsetDecoder getDecoder()
+ {
+ return currentDecoder == null ? defaultDecoder : currentDecoder;
+ }
+
+ void setCharset( Charset charset )
+ {
+ if ( charset.name().equals( defaultDecoder.charset().name() ) )
{
- return tokens.size() == 14 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ currentDecoder = defaultDecoder;
}
- else if ( event.isJvmExitError() )
+ else
{
- return tokens.size() == 6 ? FrameCompletion.COMPLETE : FrameCompletion.NOT_COMPLETE;
+ currentDecoder = charset.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
}
}
- return FrameCompletion.NOT_COMPLETE;
}
- static String decode( String line, Charset encoding )
+ static class Segment
{
- // ForkedChannelEncoder is encoding the stream with US_ASCII
- return line == null || "-".equals( line )
- ? null
- : new String( BASE64.decode( line.getBytes( US_ASCII ) ), encoding );
- }
+ private final byte[] array;
+ private final int fromIndex;
+ private final int length;
+ private final int hashCode;
- private static StackTraceWriter decodeTrace( Charset encoding, String encTraceMessage,
- String encSmartTrimmedStackTrace, String encStackTrace )
- {
- String traceMessage = decode( encTraceMessage, encoding );
- String stackTrace = decode( encStackTrace, encoding );
- String smartTrimmedStackTrace = decode( encSmartTrimmedStackTrace, encoding );
- boolean exists = traceMessage != null || stackTrace != null || smartTrimmedStackTrace != null;
- return exists ? new DeserializedStacktraceWriter( traceMessage, smartTrimmedStackTrace, stackTrace ) : null;
- }
+ Segment( byte[] array, int fromIndex, int length )
+ {
+ this.array = array;
+ this.fromIndex = fromIndex;
+ this.length = length;
- static TestSetReportEntry decodeReportEntry( Charset encoding,
- // ReportEntry:
- String encSource, String encSourceText, String encName,
- String encNameText, String encGroup, String encMessage,
- String encTimeElapsed,
- // StackTraceWriter:
- String encTraceMessage,
- String encSmartTrimmedStackTrace, String encStackTrace )
- throws NumberFormatException
- {
- if ( encoding == null )
+ int hashCode = 0;
+ int i = fromIndex;
+ for ( int loops = length >> 1; loops-- != 0; )
+ {
+ hashCode = 31 * hashCode + array[i++];
+ hashCode = 31 * hashCode + array[i++];
+ }
+ this.hashCode = i == fromIndex + length ? hashCode : 31 * hashCode + array[i];
+ }
+
+ @Override
+ public int hashCode()
{
- // corrupted or incomplete stream
- return null;
+ return hashCode;
}
- String source = decode( encSource, encoding );
- String sourceText = decode( encSourceText, encoding );
- String name = decode( encName, encoding );
- String nameText = decode( encNameText, encoding );
- String group = decode( encGroup, encoding );
- StackTraceWriter stackTraceWriter =
- decodeTrace( encoding, encTraceMessage, encSmartTrimmedStackTrace, encStackTrace );
- Integer elapsed = decodeToInteger( encTimeElapsed );
- String message = decode( encMessage, encoding );
- return reportEntry( source, sourceText, name, nameText,
- group, stackTraceWriter, elapsed, message, Collections.<String, String>emptyMap() );
- }
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( !( obj instanceof Segment ) )
+ {
+ return false;
+ }
- static Integer decodeToInteger( String line )
- {
- return line == null || "-".equals( line ) ? null : Integer.decode( line );
- }
+ Segment that = (Segment) obj;
+ if ( that.length != length )
+ {
+ return false;
+ }
- private static boolean isJvmError( String line )
- {
- String lineLower = line.toLowerCase();
- for ( String errorPattern : JVM_ERROR_PATTERNS )
- {
- if ( lineLower.contains( errorPattern ) )
+ for ( int i = 0; i < length; i++ )
{
- return true;
+ if ( that.array[that.fromIndex + i] != array[fromIndex + i] )
+ {
+ return false;
+ }
}
+ return true;
}
- return false;
}
/**
- * Determines whether the frame is complete or malformed.
+ *
*/
- private enum FrameCompletion
+ static class MalformedFrameException extends Exception
{
- NOT_COMPLETE,
- COMPLETE,
- MALFORMED
+ private final int readFrom;
+ private final int readTo;
+
+ MalformedFrameException( int readFrom, int readTo )
+ {
+ this.readFrom = readFrom;
+ this.readTo = readTo;
+ }
+
+ boolean hasValidPositions()
+ {
+ return readFrom != NO_POSITION && readTo != NO_POSITION && readTo - readFrom > 0;
+ }
}
}
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 8d3a3e5..8887e4d 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
@@ -45,6 +45,7 @@ import javax.annotation.Nonnull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
+import java.io.File;
import java.io.PrintStream;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
@@ -57,7 +58,13 @@ import java.util.concurrent.TimeUnit;
import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
import static org.apache.maven.surefire.api.util.internal.Channels.newChannel;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.MapAssert.entry;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -193,20 +200,27 @@ public class ForkingRunListenerTest
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
- byte[] cmd = ":maven-surefire-event:sys-prop:normal-run:UTF-8:azE=:djE=:\n".getBytes();
+ byte[] cmd = ( ":maven-surefire-event:\u0008:sys-prop:" + (char) 10 + ":normal-run:\u0005:UTF-8:"
+ + "\u0000\u0000\u0000\u0002:k1:\u0000\u0000\u0000\u0002:v1:\n" ).getBytes();
for ( Event e : streamToEvent( cmd ) )
{
forkStreamClient.handleEvent( e );
}
- cmd = "\n:maven-surefire-event:sys-prop:normal-run:UTF-8:azI=:djI=:\n".getBytes();
+ cmd = ( "\n:maven-surefire-event:\u0008:sys-prop:" + (char) 10 + ":normal-run:\u0005:UTF-8:"
+ + "\u0000\u0000\u0000\u0002:k2:\u0000\u0000\u0000\u0002:v2:\n" ).getBytes();
for ( Event e : streamToEvent( cmd ) )
{
forkStreamClient.handleEvent( e );
}
- assertTrue( forkStreamClient.getTestVmSystemProperties().size() == 2 );
- assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k1" ) );
- assertTrue( forkStreamClient.getTestVmSystemProperties().containsKey( "k2" ) );
+ assertThat( forkStreamClient.getTestVmSystemProperties() )
+ .hasSize( 2 );
+
+ assertThat( forkStreamClient.getTestVmSystemProperties() )
+ .includes( entry( "k1", "v1" ) );
+
+ assertThat( forkStreamClient.getTestVmSystemProperties() )
+ .includes( entry( "k2", "v2" ) );
}
public void testMultipleEntries() throws Exception
@@ -286,12 +300,15 @@ public class ForkingRunListenerTest
CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
when( arguments.getConsoleLogger() ).thenReturn( logger );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( stream ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, handler, countdown, arguments ) )
{
t.start();
countdown.awaitClosed();
+ verifyZeroInteractions( logger );
+ verify( arguments, never() ).dumpStreamText( anyString() );
for ( int i = 0, size = handler.countEventsInCache(); i < size; i++ )
{
events.add( handler.pullEvent() );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
index dc435b5..3d58ade 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MainClass.java
@@ -34,7 +34,7 @@ public class MainClass
}
else
{
- System.out.println( ":maven-surefire-event:bye:" );
+ System.out.println( ":maven-surefire-event:\u0003:bye:" );
String byeAck = ":maven-surefire-command:bye-ack:";
byte[] cmd = new byte[byeAck.length()];
int len = System.in.read( cmd );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
index 548c3e6..60d48f3 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
@@ -67,8 +67,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import static java.nio.channels.Channels.newChannel;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_DEBUG;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_ERR;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_INFO;
@@ -177,8 +175,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -206,8 +202,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -235,8 +229,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -264,8 +256,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -293,8 +283,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -322,8 +310,6 @@ public class ForkClientTest
assertThat( eventHandler.sizeOfEventCache() )
.isEqualTo( 0 );
- verify( logger ).isDebugEnabled();
-
verifyNoMoreInteractions( logger );
}
@@ -373,24 +359,22 @@ public class ForkClientTest
@Test
public void shouldLogJvmMessageAndProcessEvent() throws Exception
{
- String nativeStream = "Listening for transport dt_socket at address: bla\n:maven-surefire-event:bye:\n";
+ String nativeStream = "Listening for transport dt_socket at address: bla\n:maven-surefire-event:\u0003:bye:\n";
EH eventHandler = new EH();
CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
- ConsoleLogger logger = mock( ConsoleLogger.class );
- when( logger.isDebugEnabled() )
- .thenReturn( false );
- when( logger.isInfoEnabled() )
- .thenReturn( true );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
+ ConsoleLogger logger = mock( ConsoleLogger.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
when( logger.isDebugEnabled() ).thenReturn( true );
- when( logger.isInfoEnabled() ).thenReturn( false );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( nativeStream.getBytes() ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
Event event = eventHandler.pullEvent();
+ assertThat( event )
+ .isNotNull();
assertThat( event.isControlCategory() )
.isTrue();
assertThat( event.getEventType() )
@@ -745,10 +729,9 @@ public class ForkClientTest
@Test
public void shouldLogConsoleErrorWithStackTrace() throws Exception
{
- String nativeStream = ":maven-surefire-event:console-error-log:UTF-8"
- + ":" + encodeBase64String( "Listening for transport dt_socket at address: 5005".getBytes( UTF_8 ) )
- + ":" + encodeBase64String( "s1".getBytes( UTF_8 ) )
- + ":" + encodeBase64String( "s2".getBytes( UTF_8 ) ) + ":";
+ String nativeStream = ":maven-surefire-event:\u0011:console-error-log:\u0005:UTF-8"
+ + ":\u0000\u0000\u0000\u0032:Listening for transport dt_socket at address: 5005"
+ + ":\u0000\u0000\u0000\u0002:s1:\u0000\u0000\u0000\u0002:s2:";
EH eventHandler = new EH();
CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 1 );
ConsoleLogger logger = mock( ConsoleLogger.class );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java
index a859c76..3c1fd37 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java
@@ -123,7 +123,7 @@ public class ThreadedStreamConsumerTest
}
@Test
- public void test3() throws Exception
+ public void testBasicStatus() throws Exception
{
final QueueSynchronizer<String> sync = new QueueSynchronizer<>( 2, null );
sync.pushNext( "1" );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
index 34946ef..c420644 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
@@ -19,9 +19,12 @@ package org.apache.maven.plugin.surefire.extensions;
* under the License.
*/
+import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.api.event.Event;
+import org.apache.maven.surefire.api.report.ConsoleOutputCapture;
import org.apache.maven.surefire.api.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.booter.spi.SurefireMasterProcessChannelProcessorFactory;
import org.apache.maven.surefire.extensions.EventHandler;
@@ -33,6 +36,8 @@ import org.junit.rules.ExpectedException;
import javax.annotation.Nonnull;
import java.io.Closeable;
+import java.io.File;
+import java.io.PrintStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
@@ -46,7 +51,6 @@ import java.util.concurrent.atomic.AtomicLong;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -65,11 +69,7 @@ public class E2ETest
@Test
public void endToEndTest() throws Exception
{
- ConsoleLogger logger = mock( ConsoleLogger.class );
- ForkNodeArguments arguments = mock( ForkNodeArguments.class );
- when( arguments.getForkChannelId() ).thenReturn( 1 );
- when( arguments.getConsoleLogger() ).thenReturn( logger );
- when( arguments.getSessionId() ).thenReturn( UUID.randomUUID().toString() );
+ ForkNodeArguments arguments = new Arguments( UUID.randomUUID().toString(), 1, new NullConsoleLogger() );
final SurefireForkChannel server = new SurefireForkChannel( arguments );
final String connection = server.getForkNodeConnectionString();
@@ -84,6 +84,8 @@ public class E2ETest
final CountDownLatch awaitHandlerFinished = new CountDownLatch( 2 );
+ final int totalCalls = 400_000; // 400_000; // 1_000_000; // 10_000_000;
+
Thread t = new Thread()
{
@Override
@@ -98,23 +100,23 @@ public class E2ETest
}
};
- //PrintStream out = System.out;
- //PrintStream err = System.err;
+ PrintStream out = System.out;
+ PrintStream err = System.err;
- //ConsoleOutputCapture.startCapture( target );
+ ConsoleOutputCapture.startCapture( target );
try
{
long t1 = System.currentTimeMillis();
- for ( int i = 0; i < 400_000; i++ )
+ for ( int i = 0; i < totalCalls; i++ )
{
- //System.out.println( LONG_STRING );
- encoder.stdOut( LONG_STRING, true );
+ System.out.println( LONG_STRING );
+ //encoder.stdOut( LONG_STRING, true );
}
long t2 = System.currentTimeMillis();
long spent = t2 - t1;
- //System.setOut( out );
- //System.setErr( err );
+ System.setOut( out );
+ System.setErr( err );
System.out.println( spent + "ms on write" );
awaitHandlerFinished.countDown();
}
@@ -149,12 +151,12 @@ public class E2ETest
long t2 = System.currentTimeMillis();
long spent = t2 - t1;
- if ( counter.get() % 100_000 == 0 )
+ if ( counter.get() % 500_000 == 0 )
{
System.out.println( spent + "ms: " + counter.get() );
}
- if ( counter.get() == 320_000 )
+ if ( counter.get() == totalCalls - 64 * 1024 )
{
readTime.set( spent );
System.out.println( spent + "ms on read" );
@@ -168,17 +170,9 @@ public class E2ETest
}
};
- Closeable c = new Closeable()
- {
- @Override
- public void close()
- {
- }
- };
+ ThreadedStreamConsumer queue = new ThreadedStreamConsumer( h );
- ReadableByteChannel stdOut = mock( ReadableByteChannel.class );
- when( stdOut.read( any( ByteBuffer.class ) ) ).thenReturn( -1 );
- server.bindEventHandler( h, new CountdownCloseable( c, 1 ), stdOut )
+ server.bindEventHandler( queue, new CountdownCloseable( new DummyCloseable(), 1 ), new DummyReadableChannel() )
.start();
assertThat( awaitHandlerFinished.await( 30L, TimeUnit.SECONDS ) )
@@ -186,11 +180,11 @@ public class E2ETest
factory.close();
server.close();
+ queue.close();
- // 2 seconds while using the encoder/decoder
- // 160 millis of sending pure data without encoder/decoder
+ // 1.0 seconds while using the encoder/decoder
assertThat( readTime.get() )
- .describedAs( "The performance test should assert 2s of read time. "
+ .describedAs( "The performance test should assert 1.0s of read time. "
+ "The limit 6s guarantees that the read time does not exceed this limit on overloaded CPU." )
.isPositive()
.isLessThanOrEqualTo( 6_000L );
@@ -261,4 +255,85 @@ public class E2ETest
fail( task.get() );
}
}
+
+ private static class DummyReadableChannel implements ReadableByteChannel
+ {
+ @Override
+ public int read( ByteBuffer dst )
+ {
+ return 0;
+ }
+
+ @Override
+ public boolean isOpen()
+ {
+ return false;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+ }
+
+ private static class DummyCloseable implements Closeable
+ {
+ @Override
+ public void close()
+ {
+ }
+ }
+
+ private static class Arguments implements ForkNodeArguments
+ {
+ private final String sessionId;
+ private final int id;
+ private final ConsoleLogger logger;
+
+ private Arguments( String sessionId, int id, ConsoleLogger logger )
+ {
+ this.sessionId = sessionId;
+ this.id = id;
+ this.logger = logger;
+ }
+
+ @Nonnull
+ @Override
+ public String getSessionId()
+ {
+ return sessionId;
+ }
+
+ @Override
+ public int getForkChannelId()
+ {
+ return id;
+ }
+
+ @Nonnull
+ @Override
+ public File dumpStreamText( @Nonnull String text )
+ {
+ return new File( "" );
+ }
+
+ @Nonnull
+ @Override
+ public File dumpStreamException( @Nonnull Throwable t )
+ {
+ return new File( "" );
+ }
+
+ @Override
+ public void logWarningAtEnd( @Nonnull String text )
+ {
+ }
+
+ @Nonnull
+ @Override
+ public ConsoleLogger getConsoleLogger()
+ {
+ return logger;
+ }
+ }
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java
new file mode 100644
index 0000000..63287df
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java
@@ -0,0 +1,1237 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThread.Memento;
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThread.Segment;
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
+import org.apache.maven.surefire.api.event.ConsoleDebugEvent;
+import org.apache.maven.surefire.api.event.ConsoleErrorEvent;
+import org.apache.maven.surefire.api.event.ConsoleInfoEvent;
+import org.apache.maven.surefire.api.event.ConsoleWarningEvent;
+import org.apache.maven.surefire.api.event.ControlByeEvent;
+import org.apache.maven.surefire.api.event.ControlNextTestEvent;
+import org.apache.maven.surefire.api.event.ControlStopOnNextTestEvent;
+import org.apache.maven.surefire.api.event.Event;
+import org.apache.maven.surefire.api.event.JvmExitErrorEvent;
+import org.apache.maven.surefire.api.event.StandardStreamErrEvent;
+import org.apache.maven.surefire.api.event.StandardStreamErrWithNewLineEvent;
+import org.apache.maven.surefire.api.event.StandardStreamOutEvent;
+import org.apache.maven.surefire.api.event.StandardStreamOutWithNewLineEvent;
+import org.apache.maven.surefire.api.event.SystemPropertyEvent;
+import org.apache.maven.surefire.api.event.TestAssumptionFailureEvent;
+import org.apache.maven.surefire.api.event.TestErrorEvent;
+import org.apache.maven.surefire.api.event.TestFailedEvent;
+import org.apache.maven.surefire.api.event.TestSkippedEvent;
+import org.apache.maven.surefire.api.event.TestStartingEvent;
+import org.apache.maven.surefire.api.event.TestSucceededEvent;
+import org.apache.maven.surefire.api.event.TestsetCompletedEvent;
+import org.apache.maven.surefire.api.event.TestsetStartingEvent;
+import org.apache.maven.surefire.api.report.RunMode;
+import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.ForkNodeArguments;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+import org.fest.assertions.Condition;
+import org.junit.Test;
+
+import javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.File;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.CharsetDecoder;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.lang.Math.min;
+import static java.nio.charset.CodingErrorAction.REPLACE;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Arrays.asList;
+import static java.util.Arrays.copyOfRange;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType.DATA_INT;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType.DATA_STRING;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType.END_OF_FRAME;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType.RUN_MODE;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.SegmentType.STRING_ENCODING;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.mapEventTypes;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.mapRunModes;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.nextSegmentType;
+import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.toEvent;
+import static org.apache.maven.surefire.api.booter.Constants.DEFAULT_STREAM_ENCODING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_JVM_EXIT_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
+import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ * The performance of "get( Integer )" is 13.5 nano seconds on i5/2.6GHz:
+ * <pre>
+ * {@code
+ * TreeMap<Integer, ForkedProcessEventType> map = new TreeMap<>();
+ * map.get( hash );
+ * }
+ * </pre>
+ *
+ * <br> The performance of getting event type by Segment is 33.7 nano seconds:
+ * <pre>
+ * {@code
+ * Map<Segment, ForkedProcessEventType> map = new HashMap<>();
+ * byte[] array = ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes( UTF_8 );
+ * map.get( new Segment( array, 0, array.length ) );
+ * }
+ * </pre>
+ *
+ * <br> The performance of decoder:
+ * <pre>
+ * {@code
+ * CharsetDecoder decoder = STREAM_ENCODING.newDecoder()
+ * .onMalformedInput( REPLACE )
+ * .onUnmappableCharacter( REPLACE );
+ * ByteBuffer buffer = ByteBuffer.wrap( ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes( UTF_8 ) );
+ * CharBuffer chars = CharBuffer.allocate( 100 );
+ * decoder.reset().decode( buffer, chars, true );
+ *
+ * String s = chars.flip().toString(); // 37 nanos = CharsetDecoder + toString
+ *
+ * buffer.clear();
+ * chars.clear();
+ *
+ * ForkedProcessEventType.byOpcode( s ); // 65 nanos = CharsetDecoder + toString + byOpcode
+ * }
+ * </pre>
+ *
+ * <br> The performance of decoding 100 bytes via CharacterDecoder - 71 nano seconds:
+ * <pre>
+ * {@code
+ * decoder.reset()
+ * .decode( buffer, chars, true ); // CharsetDecoder 71 nanos
+ * chars.flip().toString(); // CharsetDecoder + toString = 91 nanos
+ * }
+ * </pre>
+ *
+ * <br> The performance of a pure string creation (instead of decoder) - 31.5 nano seconds:
+ * <pre>
+ * {@code
+ * byte[] b = {};
+ * new String( b, UTF_8 );
+ * }
+ * </pre>
+ *
+ * <br> The performance of CharsetDecoder with empty ByteBuffer:
+ * <pre>
+ * {@code
+ * CharsetDecoder + ByteBuffer.allocate( 0 ) makes 11.5 nanos
+ * CharsetDecoder + ByteBuffer.allocate( 0 ) + toString() makes 16.1 nanos
+ * }
+ * </pre>
+ */
+@SuppressWarnings( "checkstyle:magicnumber" )
+public class EventConsumerThreadTest
+{
+ private static final CountdownCloseable COUNTDOWN_CLOSEABLE = new CountdownCloseable( new MockCloseable(), 0 );
+
+ private static final String PATTERN1 =
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
+
+ private static final String PATTERN2 = "€ab©c";
+
+ private static final byte[] PATTERN2_BYTES =
+ new byte[]{(byte) -30, (byte) -126, (byte) -84, 'a', 'b', (byte) 0xc2, (byte) 0xa9, 'c'};
+
+ @Test
+ public void shouldDecodeHappyCase() throws Exception
+ {
+ CharsetDecoder decoder = UTF_8.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ ByteBuffer input = ByteBuffer.allocate( 1024 );
+ input.put( PATTERN2_BYTES )
+ .flip();
+ int bytesToDecode = PATTERN2_BYTES.length;
+ CharBuffer output = CharBuffer.allocate( 1024 );
+ int readBytes =
+ invokeMethod( EventConsumerThread.class, "decodeString", decoder, input, output, bytesToDecode, true, 0 );
+
+ assertThat( readBytes )
+ .isEqualTo( bytesToDecode );
+
+ assertThat( output.flip().toString() )
+ .isEqualTo( PATTERN2 );
+ }
+
+ @Test
+ public void shouldDecodeShifted() throws Exception
+ {
+ CharsetDecoder decoder = UTF_8.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ ByteBuffer input = ByteBuffer.allocate( 1024 );
+ input.put( PATTERN1.getBytes( UTF_8 ) )
+ .put( 90, (byte) 'A' )
+ .put( 91, (byte) 'B' )
+ .put( 92, (byte) 'C' )
+ .position( 90 );
+ CharBuffer output = CharBuffer.allocate( 1024 );
+ int readBytes =
+ invokeMethod( EventConsumerThread.class, "decodeString", decoder, input, output, 2, true, 0 );
+
+ assertThat( readBytes )
+ .isEqualTo( 2 );
+
+ assertThat( output.flip().toString() )
+ .isEqualTo( "AB" );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotDecode() throws Exception
+ {
+ CharsetDecoder decoder = UTF_8.newDecoder();
+ ByteBuffer input = ByteBuffer.allocate( 100 );
+ int bytesToDecode = 101;
+ CharBuffer output = CharBuffer.allocate( 1000 );
+ invokeMethod( EventConsumerThread.class, "decodeString", decoder, input, output, bytesToDecode, true, 0 );
+ }
+
+ @Test
+ public void shouldReadInt() throws Exception
+ {
+ Channel channel = new Channel( new byte[] {0x01, 0x02, 0x03, 0x04, ':'}, 1 );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ assertThat( thread.readInt( memento ) )
+ .isEqualTo( new BigInteger( new byte[] {0x01, 0x02, 0x03, 0x04} ).intValue() );
+ }
+
+ @Test
+ public void shouldReadInteger() throws Exception
+ {
+ Channel channel = new Channel( new byte[] {(byte) 0xff, 0x01, 0x02, 0x03, 0x04, ':'}, 1 );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ assertThat( thread.readInteger( memento ) )
+ .isEqualTo( new BigInteger( new byte[] {0x01, 0x02, 0x03, 0x04} ).intValue() );
+ }
+
+ @Test
+ public void shouldReadNullInteger() throws Exception
+ {
+ Channel channel = new Channel( new byte[] {(byte) 0x00, ':'}, 1 );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ assertThat( thread.readInteger( memento ) )
+ .isNull();
+ }
+
+ @Test( expected = EOFException.class )
+ public void shouldNotReadString() throws Exception
+ {
+ Channel channel = new Channel( PATTERN1.getBytes(), PATTERN1.length() );
+ channel.read( ByteBuffer.allocate( 100 ) );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ thread.readString( memento, 10 );
+ }
+
+ @Test
+ public void shouldReadString() throws Exception
+ {
+ Channel channel = new Channel( PATTERN1.getBytes(), PATTERN1.length() );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ String s = thread.readString( memento, 10 );
+ assertThat( s )
+ .isEqualTo( "0123456789" );
+ }
+
+ @Test
+ public void shouldReadStringShiftedBuffer() throws Exception
+ {
+ StringBuilder s = new StringBuilder( 1100 );
+ for ( int i = 0; i < 11; i++ )
+ {
+ s.append( PATTERN1 );
+ }
+
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ // whatever position will be compacted to 0
+ memento.bb.position( 974 ).limit( 974 );
+ assertThat( thread.readString( memento, PATTERN1.length() + 3 ) )
+ .isEqualTo( PATTERN1 + "012" );
+ }
+
+ @Test
+ public void shouldReadStringShiftedInput() throws Exception
+ {
+ StringBuilder s = new StringBuilder( 1100 );
+ for ( int i = 0; i < 11; i++ )
+ {
+ s.append( PATTERN1 );
+ }
+
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
+ channel.read( ByteBuffer.allocate( 997 ) );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.limit( 0 );
+ assertThat( thread.readString( memento, PATTERN1.length() ) )
+ .isEqualTo( "789" + PATTERN1.substring( 0, 97 ) );
+ }
+
+ @Test
+ public void shouldReadMultipleStringsAndShiftedInput() throws Exception
+ {
+ StringBuilder s = new StringBuilder( 5000 );
+
+ for ( int i = 0; i < 50; i++ )
+ {
+ s.append( PATTERN1 );
+ }
+
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
+ channel.read( ByteBuffer.allocate( 1997 ) );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ // whatever position will be compacted to 0
+ memento.bb.position( 974 ).limit( 974 );
+
+ StringBuilder expected = new StringBuilder( "789" );
+ for ( int i = 0; i < 11; i++ )
+ {
+ expected.append( PATTERN1 );
+ }
+ expected.setLength( 1100 );
+ assertThat( thread.readString( memento, 1100 ) )
+ .isEqualTo( expected.toString() );
+ }
+
+ @Test
+ public void shouldDecode3BytesEncodedSymbol() throws Exception
+ {
+ byte[] encodedSymbol = new byte[] {(byte) -30, (byte) -126, (byte) -84};
+ int countSymbols = 1024;
+ byte[] input = new byte[encodedSymbol.length * countSymbols];
+ for ( int i = 0; i < countSymbols; i++ )
+ {
+ System.arraycopy( encodedSymbol, 0, input, encodedSymbol.length * i, encodedSymbol.length );
+ }
+
+ Channel channel = new Channel( input, 2 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ String decodedOutput = thread.readString( memento, input.length );
+
+ assertThat( decodedOutput )
+ .isEqualTo( new String( input, 0, input.length, UTF_8 ) );
+ }
+
+ @Test
+ public void shouldDecode100Bytes()
+ {
+ CharsetDecoder decoder = DEFAULT_STREAM_ENCODING.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ // empty stream: CharsetDecoder + ByteBuffer.allocate( 0 ) makes 11.5 nanos
+ // empty stream: CharsetDecoder + ByteBuffer.allocate( 0 ) + toString() makes 16.1 nanos
+ ByteBuffer buffer = ByteBuffer.wrap( PATTERN1.getBytes( UTF_8 ) );
+ CharBuffer chars = CharBuffer.allocate( 100 );
+ /* uncomment this section for a proper measurement of the exec time
+ TimeUnit.SECONDS.sleep( 2 );
+ System.gc();
+ TimeUnit.SECONDS.sleep( 5 );
+ */
+ String s = null;
+ long l1 = System.currentTimeMillis();
+ for ( int i = 0; i < 10_000_000; i++ )
+ {
+ decoder.reset()
+ .decode( buffer, chars, true ); // CharsetDecoder 71 nanos
+ s = chars.flip().toString(); // CharsetDecoder + toString = 91 nanos
+ buffer.clear();
+ chars.clear();
+ }
+ long l2 = System.currentTimeMillis();
+ System.out.println( "decoded 100 bytes within " + ( l2 - l1 ) + " millis (10 million cycles)" );
+ assertThat( s )
+ .isEqualTo( PATTERN1 );
+ }
+
+ @Test( timeout = 60_000L )
+ public void performanceTest() throws Exception
+ {
+ final long[] staredAt = {0};
+ final long[] finishedAt = {0};
+ final AtomicInteger calls = new AtomicInteger();
+ final int totalCalls = 1_000_000; // 400_000; // 1_000_000; // 10_000_000;
+
+ EventHandler<Event> handler = new EventHandler<Event>()
+ {
+ @Override
+ public void handleEvent( @Nonnull Event event )
+ {
+ if ( staredAt[0] == 0 )
+ {
+ staredAt[0] = System.currentTimeMillis();
+ }
+
+ if ( calls.incrementAndGet() == totalCalls )
+ {
+ finishedAt[0] = System.currentTimeMillis();
+ }
+ }
+ };
+
+ final ByteBuffer event = ByteBuffer.allocate( 192 );
+ event.put( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ event.put( (byte) 14 );
+ event.put( ":std-out-stream:".getBytes( UTF_8 ) );
+ event.put( (byte) 10 );
+ event.put( ":normal-run:".getBytes( UTF_8 ) );
+ event.put( (byte) 5 );
+ event.put( ":UTF-8:".getBytes( UTF_8 ) );
+ event.putInt( 100 );
+ event.put(
+ ":0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789:"
+ .getBytes( UTF_8 ) );
+
+ event.flip();
+ byte[] frame = copyOfRange( event.array(), event.arrayOffset(), event.arrayOffset() + event.remaining() );
+ ReadableByteChannel channel = new Channel( frame, 1024 )
+ {
+ private int countRounds;
+
+ @Override
+ public int read( ByteBuffer dst )
+ {
+ int length = super.read( dst );
+ if ( length == -1 && countRounds < totalCalls )
+ {
+ i = 0;
+ length = super.read( dst );
+ countRounds++;
+ }
+ return length;
+ }
+ };
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel, handler,
+ new CountdownCloseable( new MockCloseable(), 1 ), new MockForkNodeArguments() );
+
+ TimeUnit.SECONDS.sleep( 2 );
+ System.gc();
+ TimeUnit.SECONDS.sleep( 5 );
+
+ System.out.println( "Staring the event thread..." );
+
+ thread.start();
+ thread.join();
+
+ long execTime = finishedAt[0] - staredAt[0];
+ System.out.println( execTime );
+
+ // 0.6 seconds while using the encoder/decoder
+ assertThat( execTime )
+ .describedAs( "The performance test should assert 1.0s of read time. "
+ + "The limit 3.6s guarantees that the read time does not exceed this limit on overloaded CPU." )
+ .isPositive()
+ .isLessThanOrEqualTo( 3_600L );
+ }
+
+ @Test
+ public void shouldReadEventType() throws Exception
+ {
+ Map<Segment, ForkedProcessEventType> eventTypes = mapEventTypes();
+ assertThat( eventTypes )
+ .hasSize( ForkedProcessEventType.values().length );
+
+ byte[] stream = ":maven-surefire-event:\u000E:std-out-stream:".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ ForkedProcessEventType eventType = thread.readEventType( eventTypes, memento );
+ assertThat( eventType )
+ .isEqualTo( BOOTERCODE_STDOUT );
+ }
+
+ @Test( expected = EOFException.class )
+ public void shouldEventTypeReachedEndOfStream() throws Exception
+ {
+ Map<Segment, ForkedProcessEventType> eventTypes = mapEventTypes();
+ assertThat( eventTypes )
+ .hasSize( ForkedProcessEventType.values().length );
+
+ byte[] stream = ":maven-surefire-event:\u000E:xxx".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+ thread.readEventType( eventTypes, memento );
+ }
+
+ @Test( expected = EventConsumerThread.MalformedFrameException.class )
+ public void shouldEventTypeReachedMalformedHeader() throws Exception
+ {
+ Map<Segment, ForkedProcessEventType> eventTypes = mapEventTypes();
+ assertThat( eventTypes )
+ .hasSize( ForkedProcessEventType.values().length );
+
+ byte[] stream = ":xxxxx-xxxxxxxx-xxxxx:\u000E:xxx".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+ thread.readEventType( eventTypes, memento );
+ }
+
+ @Test
+ public void shouldMapSegmentToEventType()
+ {
+ Map<Segment, RunMode> map = mapRunModes();
+
+ assertThat( map )
+ .hasSize( 2 );
+
+ byte[] stream = "normal-run".getBytes( US_ASCII );
+ Segment segment = new Segment( stream, 0, stream.length );
+ assertThat( map.get( segment ) )
+ .isEqualTo( NORMAL_RUN );
+
+ stream = "rerun-test-after-failure".getBytes( US_ASCII );
+ segment = new Segment( stream, 0, stream.length );
+ assertThat( map.get( segment ) )
+ .isEqualTo( RERUN_TEST_AFTER_FAILURE );
+ }
+
+ @Test
+ public void shouldReadEmptyString() throws Exception
+ {
+ byte[] stream = "\u0000\u0000\u0000\u0000::".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readString( memento ) )
+ .isEmpty();
+ }
+
+ @Test
+ public void shouldReadNullString() throws Exception
+ {
+ byte[] stream = "\u0000\u0000\u0000\u0001:\u0000:".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readString( memento ) )
+ .isNull();
+ }
+
+ @Test
+ public void shouldReadSingleCharString() throws Exception
+ {
+ byte[] stream = "\u0000\u0000\u0000\u0001:A:".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readString( memento ) )
+ .isEqualTo( "A" );
+ }
+
+ @Test
+ public void shouldReadThreeCharactersString() throws Exception
+ {
+ byte[] stream = "\u0000\u0000\u0000\u0003:ABC:".getBytes( UTF_8 );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readString( memento ) )
+ .isEqualTo( "ABC" );
+ }
+
+ @Test
+ public void shouldReadDefaultCharset() throws Exception
+ {
+ byte[] stream = "\u0005:UTF-8:".getBytes( US_ASCII );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readCharset( memento ) )
+ .isNotNull()
+ .isEqualTo( UTF_8 );
+ }
+
+ @Test
+ public void shouldReadNonDefaultCharset() throws Exception
+ {
+ byte[] stream = ( (char) 10 + ":ISO_8859_1:" ).getBytes( US_ASCII );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ assertThat( thread.readCharset( memento ) )
+ .isNotNull()
+ .isEqualTo( ISO_8859_1 );
+ }
+
+ @Test
+ public void shouldSetNonDefaultCharset()
+ {
+ byte[] stream = {};
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+ Memento memento = thread.new Memento();
+
+ memento.setCharset( ISO_8859_1 );
+ assertThat( memento.getDecoder().charset() ).isEqualTo( ISO_8859_1 );
+
+ memento.setCharset( UTF_8 );
+ assertThat( memento.getDecoder().charset() ).isEqualTo( UTF_8 );
+
+ memento.reset();
+ assertThat( memento.getDecoder() ).isNotNull();
+ assertThat( memento.getDecoder().charset() ).isEqualTo( UTF_8 );
+ }
+
+ @Test( expected = EventConsumerThread.MalformedFrameException.class )
+ public void malformedCharset() throws Exception
+ {
+ byte[] stream = ( (char) 8 + ":ISO_8859:" ).getBytes( US_ASCII );
+ Channel channel = new Channel( stream, 1 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ memento.setCharset( UTF_8 );
+
+ thread.readCharset( memento );
+ }
+
+ @Test
+ public void shouldMapEventTypeToSegmentType()
+ {
+ SegmentType[] segmentTypes = nextSegmentType( BOOTERCODE_BYE );
+ assertThat( segmentTypes )
+ .hasSize( 1 )
+ .containsOnly( END_OF_FRAME );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_STOP_ON_NEXT_TEST );
+ assertThat( segmentTypes )
+ .hasSize( 1 )
+ .containsOnly( END_OF_FRAME );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_NEXT_TEST );
+ assertThat( segmentTypes )
+ .hasSize( 1 )
+ .containsOnly( END_OF_FRAME );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_CONSOLE_ERROR );
+ assertThat( segmentTypes )
+ .hasSize( 5 )
+ .satisfies( new InOrder( STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_JVM_EXIT_ERROR );
+ assertThat( segmentTypes )
+ .hasSize( 5 )
+ .satisfies( new InOrder( STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_CONSOLE_INFO );
+ assertThat( segmentTypes )
+ .hasSize( 3 )
+ .satisfies( new InOrder( STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG );
+ assertThat( segmentTypes )
+ .hasSize( 3 )
+ .satisfies( new InOrder( STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING );
+ assertThat( segmentTypes )
+ .hasSize( 3 )
+ .satisfies( new InOrder( STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_STDOUT );
+ assertThat( segmentTypes )
+ .hasSize( 4 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE );
+ assertThat( segmentTypes )
+ .hasSize( 4 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDERR );
+ assertThat( segmentTypes )
+ .hasSize( 4 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE );
+ assertThat( segmentTypes )
+ .hasSize( 4 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_SYSPROPS );
+ assertThat( segmentTypes )
+ .hasSize( 5 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_TESTSET_STARTING );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_STARTING );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_TEST_SUCCEEDED );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( BOOTERCODE_TEST_FAILED );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_ERROR );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+
+ segmentTypes = nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE );
+ assertThat( segmentTypes )
+ .hasSize( 13 )
+ .satisfies( new InOrder( RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+ DATA_STRING, DATA_STRING, DATA_INT, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME ) );
+ }
+
+ @Test
+ public void shouldCreateEvent()
+ {
+ Event event = toEvent( BOOTERCODE_BYE, NORMAL_RUN, emptyList() );
+ assertThat( event )
+ .isInstanceOf( ControlByeEvent.class );
+
+ event = toEvent( BOOTERCODE_STOP_ON_NEXT_TEST, NORMAL_RUN, emptyList() );
+ assertThat( event )
+ .isInstanceOf( ControlStopOnNextTestEvent.class );
+
+ event = toEvent( BOOTERCODE_NEXT_TEST, NORMAL_RUN, emptyList() );
+ assertThat( event )
+ .isInstanceOf( ControlNextTestEvent.class );
+
+ List data = asList( "1", "2", "3" );
+ event = toEvent( BOOTERCODE_CONSOLE_ERROR, NORMAL_RUN, data );
+ assertThat( event )
+ .isInstanceOf( ConsoleErrorEvent.class );
+ ConsoleErrorEvent consoleErrorEvent = (ConsoleErrorEvent) event;
+ assertThat( consoleErrorEvent.getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( "1" );
+ assertThat( consoleErrorEvent.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "2" );
+ assertThat( consoleErrorEvent.getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "3" );
+
+ data = asList( null, null, null );
+ event = toEvent( BOOTERCODE_CONSOLE_ERROR, NORMAL_RUN, data );
+ assertThat( event )
+ .isInstanceOf( ConsoleErrorEvent.class );
+ consoleErrorEvent = (ConsoleErrorEvent) event;
+ assertThat( consoleErrorEvent.getStackTraceWriter() )
+ .isNull();
+
+ data = asList( "1", "2", "3" );
+ event = toEvent( BOOTERCODE_JVM_EXIT_ERROR, NORMAL_RUN, data );
+ assertThat( event )
+ .isInstanceOf( JvmExitErrorEvent.class );
+ JvmExitErrorEvent jvmExitErrorEvent = (JvmExitErrorEvent) event;
+ assertThat( jvmExitErrorEvent.getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( "1" );
+ assertThat( jvmExitErrorEvent.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "2" );
+ assertThat( jvmExitErrorEvent.getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "3" );
+
+ data = asList( null, null, null );
+ event = toEvent( BOOTERCODE_JVM_EXIT_ERROR, NORMAL_RUN, data );
+ assertThat( event )
+ .isInstanceOf( JvmExitErrorEvent.class );
+ jvmExitErrorEvent = (JvmExitErrorEvent) event;
+ assertThat( jvmExitErrorEvent.getStackTraceWriter() )
+ .isNull();
+
+ data = singletonList( "m" );
+ event = toEvent( BOOTERCODE_CONSOLE_INFO, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( ConsoleInfoEvent.class );
+ assertThat( ( (ConsoleInfoEvent) event ).getMessage() ).isEqualTo( "m" );
+
+ data = singletonList( "" );
+ event = toEvent( BOOTERCODE_CONSOLE_WARNING, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( ConsoleWarningEvent.class );
+ assertThat( ( (ConsoleWarningEvent) event ).getMessage() ).isEmpty();
+
+ data = singletonList( null );
+ event = toEvent( BOOTERCODE_CONSOLE_DEBUG, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( ConsoleDebugEvent.class );
+ assertThat( ( (ConsoleDebugEvent) event ).getMessage() ).isNull();
+
+ data = singletonList( "m" );
+ event = toEvent( BOOTERCODE_STDOUT, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( StandardStreamOutEvent.class );
+ assertThat( ( (StandardStreamOutEvent) event ).getMessage() ).isEqualTo( "m" );
+ assertThat( ( (StandardStreamOutEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+
+ data = singletonList( null );
+ event = toEvent( BOOTERCODE_STDOUT_NEW_LINE, RERUN_TEST_AFTER_FAILURE, data );
+ assertThat( event ).isInstanceOf( StandardStreamOutWithNewLineEvent.class );
+ assertThat( ( (StandardStreamOutWithNewLineEvent) event ).getMessage() ).isNull();
+ assertThat( ( (StandardStreamOutWithNewLineEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+
+ data = singletonList( null );
+ event = toEvent( BOOTERCODE_STDERR, RERUN_TEST_AFTER_FAILURE, data );
+ assertThat( event ).isInstanceOf( StandardStreamErrEvent.class );
+ assertThat( ( (StandardStreamErrEvent) event ).getMessage() ).isNull();
+ assertThat( ( (StandardStreamErrEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+
+ data = singletonList( "abc" );
+ event = toEvent( BOOTERCODE_STDERR_NEW_LINE, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( StandardStreamErrWithNewLineEvent.class );
+ assertThat( ( (StandardStreamErrWithNewLineEvent) event ).getMessage() ).isEqualTo( "abc" );
+ assertThat( ( (StandardStreamErrWithNewLineEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+
+ data = asList( "key", "value" );
+ event = toEvent( BOOTERCODE_SYSPROPS, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( SystemPropertyEvent.class );
+ assertThat( ( (SystemPropertyEvent) event ).getKey() ).isEqualTo( "key" );
+ assertThat( ( (SystemPropertyEvent) event ).getValue() ).isEqualTo( "value" );
+ assertThat( ( (SystemPropertyEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+
+ data = asList( "source", "sourceText", "name", "nameText", "group", "message", 5,
+ "traceMessage", "smartTrimmedStackTrace", "stackTrace" );
+ event = toEvent( BOOTERCODE_TESTSET_STARTING, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestsetStartingEvent.class );
+ assertThat( ( (TestsetStartingEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getNameText() ).isEqualTo( "nameText" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getMessage() ).isEqualTo( "message" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestsetStartingEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( "traceMessage" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "smartTrimmedStackTrace" );
+ assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", "sourceText", "name", "nameText", "group", null, 5,
+ "traceMessage", "smartTrimmedStackTrace", "stackTrace" );
+ event = toEvent( BOOTERCODE_TESTSET_COMPLETED, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestsetCompletedEvent.class );
+ assertThat( ( (TestsetCompletedEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getNameText() ).isEqualTo( "nameText" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getMessage() ).isNull();
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestsetCompletedEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( "traceMessage" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "smartTrimmedStackTrace" );
+ assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", "sourceText", "name", "nameText", "group", "message", 5,
+ null, "smartTrimmedStackTrace", "stackTrace" );
+ event = toEvent( BOOTERCODE_TEST_STARTING, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestStartingEvent.class );
+ assertThat( ( (TestStartingEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getNameText() ).isEqualTo( "nameText" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getMessage() ).isEqualTo( "message" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestStartingEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isNull();
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "smartTrimmedStackTrace" );
+ assertThat( ( (TestStartingEvent) event ).getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", "sourceText", "name", "nameText", "group", "message", 5, null, null, null );
+ event = toEvent( BOOTERCODE_TEST_SUCCEEDED, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestSucceededEvent.class );
+ assertThat( ( (TestSucceededEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getNameText() ).isEqualTo( "nameText" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getMessage() ).isEqualTo( "message" );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestSucceededEvent) event ).getReportEntry().getStackTraceWriter() ).isNull();
+
+ data = asList( "source", null, "name", null, "group", null, 5,
+ "traceMessage", "smartTrimmedStackTrace", "stackTrace" );
+ event = toEvent( BOOTERCODE_TEST_FAILED, RERUN_TEST_AFTER_FAILURE, data );
+ assertThat( event ).isInstanceOf( TestFailedEvent.class );
+ assertThat( ( (TestFailedEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getSourceText() ).isNull();
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getNameText() ).isNull();
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getMessage() ).isNull();
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestFailedEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( "traceMessage" );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( "smartTrimmedStackTrace" );
+ assertThat( ( (TestFailedEvent) event ).getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", null, "name", null, null, null, 5, null, null, "stackTrace" );
+ event = toEvent( BOOTERCODE_TEST_SKIPPED, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestSkippedEvent.class );
+ assertThat( ( (TestSkippedEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getSourceText() ).isNull();
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getNameText() ).isNull();
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getGroup() ).isNull();
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getMessage() ).isNull();
+ assertThat( ( (TestSkippedEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestSkippedEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isNull();
+ assertThat( ( (TestSkippedEvent) event )
+ .getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isNull();
+ assertThat( ( (TestSkippedEvent) event )
+ .getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", null, "name", "nameText", null, null, 0, null, null, "stackTrace" );
+ event = toEvent( BOOTERCODE_TEST_ERROR, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestErrorEvent.class );
+ assertThat( ( (TestErrorEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getSourceText() ).isNull();
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getNameText() ).isEqualTo( "nameText" );
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getGroup() ).isNull();
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getMessage() ).isNull();
+ assertThat( ( (TestErrorEvent) event ).getReportEntry().getElapsed() ).isZero();
+ assertThat( ( (TestErrorEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isNull();
+ assertThat( ( (TestErrorEvent) event )
+ .getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isNull();
+ assertThat( ( (TestErrorEvent) event )
+ .getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+
+ data = asList( "source", null, "name", null, "group", null, 5, null, null, "stackTrace" );
+ event = toEvent( BOOTERCODE_TEST_ASSUMPTIONFAILURE, NORMAL_RUN, data );
+ assertThat( event ).isInstanceOf( TestAssumptionFailureEvent.class );
+ assertThat( ( (TestAssumptionFailureEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getSourceText() ).isNull();
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getNameText() ).isNull();
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getGroup() ).isEqualTo( "group" );
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getMessage() ).isNull();
+ assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getElapsed() ).isEqualTo( 5 );
+ assertThat( ( (TestAssumptionFailureEvent) event )
+ .getReportEntry().getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isNull();
+ assertThat( ( (TestAssumptionFailureEvent) event )
+ .getReportEntry().getStackTraceWriter().smartTrimmedStackTrace() )
+ .isNull();
+ assertThat( ( (TestAssumptionFailureEvent) event )
+ .getReportEntry().getStackTraceWriter().writeTraceToString() )
+ .isEqualTo( "stackTrace" );
+ }
+
+ private static class Channel implements ReadableByteChannel
+ {
+ private final byte[] bytes;
+ private final int chunkSize;
+ protected int i;
+
+ Channel( byte[] bytes, int chunkSize )
+ {
+ this.bytes = bytes;
+ this.chunkSize = chunkSize;
+ }
+
+ @Override
+ public int read( ByteBuffer dst )
+ {
+ if ( i == bytes.length )
+ {
+ return -1;
+ }
+ else if ( dst.hasRemaining() )
+ {
+ int length = min( min( chunkSize, bytes.length - i ), dst.remaining() ) ;
+ dst.put( bytes, i, length );
+ i += length;
+ return length;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ @Override
+ public boolean isOpen()
+ {
+ return false;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+ }
+
+ private static class MockCloseable implements Closeable
+ {
+ @Override
+ public void close()
+ {
+ }
+ }
+
+ private static class MockEventHandler<T> implements EventHandler<T>
+ {
+ @Override
+ public void handleEvent( @Nonnull T event )
+ {
+ }
+ }
+
+ private static class MockForkNodeArguments implements ForkNodeArguments
+ {
+ @Nonnull
+ @Override
+ public String getSessionId()
+ {
+ return null;
+ }
+
+ @Override
+ public int getForkChannelId()
+ {
+ return 0;
+ }
+
+ @Nonnull
+ @Override
+ public File dumpStreamText( @Nonnull String text )
+ {
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public File dumpStreamException( @Nonnull Throwable t )
+ {
+ return null;
+ }
+
+ @Override
+ public void logWarningAtEnd( @Nonnull String text )
+ {
+ }
+
+ @Nonnull
+ @Override
+ public ConsoleLogger getConsoleLogger()
+ {
+ return null;
+ }
+ }
+
+ private static class InOrder extends Condition<Object[]>
+ {
+ private final SegmentType[] expected;
+
+ InOrder( SegmentType... expected )
+ {
+ this.expected = expected;
+ }
+
+ @Override
+ public boolean matches( Object[] values )
+ {
+ if ( values == null && expected == null )
+ {
+ return true;
+ }
+ else if ( values != null && expected != null && values.length == expected.length )
+ {
+ boolean matches = true;
+ for ( int i = 0; i < values.length; i++ )
+ {
+
+ assertThat( values[i] ).isInstanceOf( SegmentType.class );
+ matches &= values[i] == expected[i];
+ }
+ return matches;
+ }
+ return false;
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
index 9d38b65..b83884a 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
@@ -62,7 +62,6 @@ import java.io.File;
import java.io.LineNumberReader;
import java.io.PrintStream;
import java.io.StringReader;
-import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.util.Map;
@@ -74,19 +73,18 @@ import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Arrays.copyOfRange;
import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
-import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
import static org.apache.maven.surefire.api.util.internal.Channels.newChannel;
import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Index.atIndex;
import static org.junit.Assert.assertTrue;
import static org.junit.rules.ExpectedException.none;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -109,15 +107,6 @@ public class ForkedProcessEventNotifierTest
public final ExpectedException rule = none();
@Test
- public void shouldBeFailSafe()
- {
- assertThat( EventConsumerThread.decode( null, UTF_8 ) ).isNull();
- assertThat( EventConsumerThread.decode( "-", UTF_8 ) ).isNull();
- assertThat( EventConsumerThread.decodeToInteger( null ) ).isNull();
- assertThat( EventConsumerThread.decodeToInteger( "-" ) ).isNull();
- }
-
- @Test
public void shouldHaveSystemProperty() throws Exception
{
final Stream out = Stream.newStream();
@@ -138,6 +127,7 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
@@ -146,7 +136,7 @@ public class ForkedProcessEventNotifierTest
notifier.notifyEvent( eventHandler.pullEvent() );
}
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.counter.get() )
.isEqualTo( props.size() );
}
@@ -154,11 +144,7 @@ public class ForkedProcessEventNotifierTest
@Test
public void shouldRecognizeEmptyStream4ReportEntry()
{
- ReportEntry reportEntry = EventConsumerThread.decodeReportEntry( null, null, null, "", "", null, null, "",
- "", "", null );
- assertThat( reportEntry ).isNull();
-
- reportEntry = EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "-", "", "", "" );
+ ReportEntry reportEntry = EventConsumerThread.newReportEntry( "", "", "", "", "", "", null, "", "", "" );
assertThat( reportEntry ).isNotNull();
assertThat( reportEntry.getStackTraceWriter() ).isNotNull();
assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() ).isEmpty();
@@ -172,9 +158,6 @@ public class ForkedProcessEventNotifierTest
assertThat( reportEntry.getNameWithGroup() ).isEmpty();
assertThat( reportEntry.getMessage() ).isEmpty();
assertThat( reportEntry.getElapsed() ).isNull();
-
- rule.expect( NumberFormatException.class );
- EventConsumerThread.decodeReportEntry( UTF_8, "", "", "", "", "", "", "", "", "", "" );
}
@Test
@@ -182,16 +165,9 @@ public class ForkedProcessEventNotifierTest
public void testCreatingReportEntry()
{
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1\ntrace line 2";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -211,15 +187,9 @@ public class ForkedProcessEventNotifierTest
when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedSourceText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceText() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedText = encodeBase64String( toArray( UTF_8.encode( reportEntry.getNameText() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- ReportEntry decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName,
- encodedSourceText, encodedName, encodedText, encodedGroup, encodedMessage, "-", null, null, null );
+ ReportEntry decodedReportEntry = EventConsumerThread.newReportEntry( reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), null, null, null, null );
assertThat( decodedReportEntry ).isNotNull();
assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
@@ -230,9 +200,9 @@ public class ForkedProcessEventNotifierTest
assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
- decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
- encodedName, encodedText, encodedGroup, encodedMessage, "-", encodedExceptionMsg,
- encodedSmartStackTrace, null );
+ decodedReportEntry = EventConsumerThread.newReportEntry( reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), null, exceptionMessage, smartStackTrace, null );
assertThat( decodedReportEntry ).isNotNull();
assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
@@ -250,9 +220,9 @@ public class ForkedProcessEventNotifierTest
assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
.isNull();
- decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
- encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
- encodedSmartStackTrace, null );
+ decodedReportEntry = EventConsumerThread.newReportEntry( reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, null );
assertThat( decodedReportEntry ).isNotNull();
assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
@@ -270,9 +240,9 @@ public class ForkedProcessEventNotifierTest
assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
.isNull();
- decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
- encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
- encodedSmartStackTrace, encodedStackTrace );
+ decodedReportEntry = EventConsumerThread.newReportEntry( reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, stackTrace );
assertThat( decodedReportEntry ).isNotNull();
assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
@@ -291,9 +261,9 @@ public class ForkedProcessEventNotifierTest
assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
- decodedReportEntry = EventConsumerThread.decodeReportEntry( UTF_8, encodedSourceName, encodedSourceText,
- encodedName, encodedText, encodedGroup, encodedMessage, "1003", encodedExceptionMsg,
- encodedSmartStackTrace, encodedTrimmedStackTrace );
+ decodedReportEntry = EventConsumerThread.newReportEntry( reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, trimmedStackTrace );
assertThat( decodedReportEntry ).isNotNull();
assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
@@ -324,7 +294,7 @@ public class ForkedProcessEventNotifierTest
String read = new String( out.toByteArray(), UTF_8 );
assertThat( read )
- .isEqualTo( ":maven-surefire-event:bye:\n" );
+ .isEqualTo( ":maven-surefire-event:\u0003:bye:" );
LineNumberReader lines = out.newReader( UTF_8 );
@@ -343,12 +313,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -363,7 +334,7 @@ public class ForkedProcessEventNotifierTest
String read = new String( out.toByteArray(), UTF_8 );
assertThat( read )
- .isEqualTo( ":maven-surefire-event:stop-on-next-test:\n" );
+ .isEqualTo( ":maven-surefire-event:\u0011:stop-on-next-test:" );
LineNumberReader lines = out.newReader( UTF_8 );
@@ -382,12 +353,14 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
+ verify( arguments, never() ).dumpStreamText( anyString() );
assertThat( listener.called.get() )
.isTrue();
}
@@ -438,7 +411,7 @@ public class ForkedProcessEventNotifierTest
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -453,7 +426,7 @@ public class ForkedProcessEventNotifierTest
String read = new String( out.toByteArray(), UTF_8 );
assertThat( read )
- .isEqualTo( ":maven-surefire-event:next-test:\n" );
+ .isEqualTo( ":maven-surefire-event:\u0009:next-test:" );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -466,12 +439,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -495,12 +469,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -524,12 +499,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -555,12 +531,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -586,12 +563,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -616,12 +594,15 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
+ verifyZeroInteractions( logger );
+
assertThat( listener.called.get() )
.isTrue();
@@ -649,12 +630,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -680,12 +662,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -711,12 +694,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -747,7 +731,7 @@ public class ForkedProcessEventNotifierTest
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -778,7 +762,7 @@ public class ForkedProcessEventNotifierTest
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -809,7 +793,7 @@ public class ForkedProcessEventNotifierTest
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -835,12 +819,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -865,12 +850,13 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
-
+ verifyZeroInteractions( logger );
assertThat( listener.called.get() )
.isTrue();
}
@@ -887,7 +873,7 @@ public class ForkedProcessEventNotifierTest
@Test
public void shouldHandleErrorAfterUnknownOperation() throws Exception
{
- String cmd = ":maven-surefire-event:abnormal-run:-:\n";
+ String cmd = ":maven-surefire-event:\u000c:abnormal-run:-:\n";
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( cmd.getBytes() ) );
@@ -905,29 +891,25 @@ public class ForkedProcessEventNotifierTest
}
ArgumentCaptor<String> dumpLine = ArgumentCaptor.forClass( String.class );
- verify( logger, times( 2 ) ).debug( dumpLine.capture() );
+ verify( logger, times( 1 ) ).debug( dumpLine.capture() );
assertThat( dumpLine.getAllValues() )
- .hasSize( 2 )
- .contains( ":maven-surefire-event:abnormal-run:", atIndex( 0 ) )
- .contains( "-:", atIndex( 1 ) );
+ .hasSize( 1 )
+ .contains( ":maven-surefire-event:\u000c:abnormal-run:-:" );
ArgumentCaptor<String> dumpText = ArgumentCaptor.forClass( String.class );
- verify( arguments, times( 2 ) ).dumpStreamText( dumpText.capture() );
+ verify( arguments, times( 1 ) ).dumpStreamText( dumpText.capture() );
String dump = "Corrupted STDOUT by directly writing to native stream in forked JVM 0.";
assertThat( dumpText.getAllValues() )
- .hasSize( 2 )
- .contains( format( dump + " Stream '%s'.", ":maven-surefire-event:abnormal-run:" ), atIndex( 0 ) )
- .contains( format( dump + " Stream '%s'.", "-:" ), atIndex( 1 ) );
+ .hasSize( 1 )
+ .contains( format( dump + " Stream '%s'.", ":maven-surefire-event:\u000c:abnormal-run:-:" ) );
ArgumentCaptor<String> warning = ArgumentCaptor.forClass( String.class );
- verify( arguments, times( 2 ) ).logWarningAtEnd( warning.capture() );
+ verify( arguments, times( 1 ) ).logWarningAtEnd( warning.capture() );
dump += " See FAQ web page and the dump file ";
assertThat( warning.getAllValues() )
- .hasSize( 2 );
+ .hasSize( 1 );
assertThat( warning.getAllValues().get( 0 ) )
.startsWith( dump );
- assertThat( warning.getAllValues().get( 1 ) )
- .startsWith( dump );
}
@Test
@@ -955,12 +937,15 @@ public class ForkedProcessEventNotifierTest
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
when( arguments.getConsoleLogger() ).thenReturn( logger );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
+ verifyZeroInteractions( logger );
+
assertThat( listener.called.get() )
.isTrue();
}
@@ -1065,12 +1050,14 @@ public class ForkedProcessEventNotifierTest
CountdownCloseable countdown = new CountdownCloseable( mock( Closeable.class ), 0 );
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkNodeArguments arguments = mock( ForkNodeArguments.class );
+ when( arguments.dumpStreamText( anyString() ) ).thenReturn( new File( "" ) );
when( arguments.getConsoleLogger() ).thenReturn( logger );
try ( EventConsumerThread t = new EventConsumerThread( "t", channel, eventHandler, countdown, arguments ) )
{
t.start();
notifier.notifyEvent( eventHandler.pullEvent() );
}
+ verifyZeroInteractions( logger );
}
}
@@ -1261,11 +1248,6 @@ public class ForkedProcessEventNotifierTest
}
}
- private static byte[] toArray( ByteBuffer buffer )
- {
- return copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
- }
-
private static class EH implements EventHandler<Event>
{
private final BlockingQueue<Event> cache = new LinkedTransferQueue<>();
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 9770f8a..7692a04 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
@@ -44,6 +44,7 @@ import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumerTest;
import org.apache.maven.plugin.surefire.extensions.ConsoleOutputReporterTest;
import org.apache.maven.plugin.surefire.extensions.E2ETest;
+import org.apache.maven.plugin.surefire.extensions.EventConsumerThreadTest;
import org.apache.maven.plugin.surefire.extensions.ForkedProcessEventNotifierTest;
import org.apache.maven.plugin.surefire.extensions.StatelessReporterTest;
import org.apache.maven.plugin.surefire.extensions.StreamFeederTest;
@@ -114,6 +115,7 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( StreamFeederTest.class ) );
suite.addTest( new JUnit4TestAdapter( E2ETest.class ) );
suite.addTest( new JUnit4TestAdapter( ThreadedStreamConsumerTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( EventConsumerThreadTest.class ) );
return suite;
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
index 16eb3a5..8caa668 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
@@ -63,6 +63,7 @@ public class ForkChannelTest
@Test( timeout = TESTCASE_TIMEOUT )
public void shouldRequestReplyMessagesViaTCP() throws Exception
{
+ final MockReporter reporter = new MockReporter();
final String sessionId = UUID.randomUUID().toString();
ForkNodeArguments forkNodeArguments = new ForkNodeArguments()
{
@@ -86,6 +87,13 @@ public class ForkChannelTest
return new File( "" );
}
+ @Nonnull
+ @Override
+ public File dumpStreamException( @Nonnull Throwable t )
+ {
+ return new File( "" );
+ }
+
@Override
public void logWarningAtEnd( @Nonnull String text )
{
@@ -95,7 +103,7 @@ public class ForkChannelTest
@Nonnull
public ConsoleLogger getConsoleLogger()
{
- return new MockReporter();
+ return reporter;
}
};
@@ -133,7 +141,7 @@ public class ForkChannelTest
CountdownCloseable cc = new CountdownCloseable( closeable, 2 );
Consumer consumer = new Consumer();
- Client client = new Client( uri.getPort(), sessionId.toString() );
+ Client client = new Client( uri.getPort(), sessionId );
client.start();
channel.connectToClient();
@@ -152,6 +160,10 @@ public class ForkChannelTest
assertThat( isCloseableCalled.await( TESTCASE_TIMEOUT, MILLISECONDS ) )
.isTrue();
+ assertThat( reporter.getEvents() )
+ .describedAs( "The decoder captured the list of stream errors: " + reporter.getData().toString() )
+ .isEmpty();
+
assertThat( consumer.lines )
.hasSize( 1 );
@@ -192,7 +204,7 @@ public class ForkChannelTest
int readLength = socket.getInputStream().read( data );
String token = new String( data, 0, readLength, US_ASCII );
assertThat( token ).isEqualTo( ":maven-surefire-command:noop:" );
- socket.getOutputStream().write( ":maven-surefire-event:bye:".getBytes( US_ASCII ) );
+ socket.getOutputStream().write( ":maven-surefire-event:\u0003:bye:".getBytes( US_ASCII ) );
}
catch ( IOException e )
{
diff --git a/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/Constants.java
similarity index 57%
copy from surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java
copy to surefire-api/src/main/java/org/apache/maven/surefire/api/booter/Constants.java
index 7bb1afe..d1be7ac 100644
--- a/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/Constants.java
@@ -1,4 +1,4 @@
-package wellFormedXmlFailures;
+package org.apache.maven.surefire.api.booter;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,44 +19,17 @@ package wellFormedXmlFailures;
* under the License.
*/
-import junit.extensions.TestSetup;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import java.nio.charset.Charset;
-public class TestSurefire3
- extends TestCase
-{
-
- public TestSurefire3( )
- {
- super( );
- }
-
- public TestSurefire3( String name )
- {
- super( name );
- }
-
-
- public void testQuote()
- {
- fail( "\"" );
- }
-
- public void testLower()
- {
- fail( "<" );
- }
-
- public void testGreater()
- {
- fail( ">" );
- }
-
- public void testU0000()
- {
- fail( "\u0000" );
- }
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
+/**
+ *
+ */
+public final class Constants
+{
+ public static final String MAGIC_NUMBER = "maven-surefire-event";
+ public static final byte[] MAGIC_NUMBER_BYTES = MAGIC_NUMBER.getBytes( US_ASCII );
+ public static final Charset DEFAULT_STREAM_ENCODING = UTF_8;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/ForkedProcessEventType.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/ForkedProcessEventType.java
index e84e5bc..94da335 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/ForkedProcessEventType.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/booter/ForkedProcessEventType.java
@@ -19,11 +19,7 @@ package org.apache.maven.surefire.api.booter;
* under the License.
*/
-import javax.annotation.Nonnull;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static java.util.Collections.unmodifiableMap;
+import static java.nio.charset.StandardCharsets.US_ASCII;
/**
* Events sent back to the plugin process.
@@ -31,54 +27,268 @@ import static java.util.Collections.unmodifiableMap;
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
+@SuppressWarnings( "checkstyle:linelength" )
public enum ForkedProcessEventType
{
- BOOTERCODE_SYSPROPS( "sys-prop" ),
+ /**
+ * This is the opcode "sys-prop". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:sys-prop:RunMode:UTF-8:0xFFFFFFFF:key:0xFFFFFFFF:value:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "sys-prop"
+ * </ul>
+ */
+ BOOTERCODE_SYSPROPS( "sys-prop" ),
+ /**
+ * This is the opcode "testset-starting". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:testset-starting:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "testset-starting"
+ * </ul>
+ */
BOOTERCODE_TESTSET_STARTING( "testset-starting" ),
+
+ /**
+ * This is the opcode "testset-completed". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:testset-completed:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "testset-completed"
+ * </ul>
+ */
BOOTERCODE_TESTSET_COMPLETED( "testset-completed" ),
+
+ /**
+ * This is the opcode "test-starting". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-starting:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-starting"
+ * </ul>
+ */
BOOTERCODE_TEST_STARTING( "test-starting" ),
+
+ /**
+ * This is the opcode "test-succeeded". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-succeeded:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-succeeded"
+ * </ul>
+ */
BOOTERCODE_TEST_SUCCEEDED( "test-succeeded" ),
+
+ /**
+ * This is the opcode "test-failed". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-failed:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-failed"
+ * </ul>
+ */
BOOTERCODE_TEST_FAILED( "test-failed" ),
+
+ /**
+ * This is the opcode "test-skipped". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-skipped:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-skipped"
+ * </ul>
+ */
BOOTERCODE_TEST_SKIPPED( "test-skipped" ),
+
+ /**
+ * This is the opcode "test-error". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-error:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-error"
+ * </ul>
+ */
BOOTERCODE_TEST_ERROR( "test-error" ),
+
+ /**
+ * This is the opcode "test-assumption-failure". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:test-assumption-failure:RunMode:UTF-8:0xFFFFFFFF:SourceName:0xFFFFFFFF:SourceText:0xFFFFFFFF:Name:0xFFFFFFFF:NameText:0xFFFFFFFF:Group:0xFFFFFFFF:Message:ElapsedTime (binary int):0xFFFFFFFF:LocalizedMessage:0xFFFFFFFF:SmartTrimmedStackTrace:0xFFFFFFFF:toStackTrace( stw, trimStackTraces ):
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "test-assumption-failure"
+ * </ul>
+ */
BOOTERCODE_TEST_ASSUMPTIONFAILURE( "test-assumption-failure" ),
+ /**
+ * This is the opcode "std-out-stream". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:std-out-stream:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "std-out-stream"
+ * </ul>
+ */
BOOTERCODE_STDOUT( "std-out-stream" ),
+
+ /**
+ * This is the opcode "std-out-stream-new-line". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:std-out-stream-new-line:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "std-out-stream-new-line"
+ * </ul>
+ */
BOOTERCODE_STDOUT_NEW_LINE( "std-out-stream-new-line" ),
+
+ /**
+ * This is the opcode "std-err-stream". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:std-err-stream:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "std-err-stream"
+ * </ul>
+ */
BOOTERCODE_STDERR( "std-err-stream" ),
+
+ /**
+ * This is the opcode "std-err-stream-new-line". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:std-err-stream-new-line:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "std-err-stream-new-line"
+ * </ul>
+ */
BOOTERCODE_STDERR_NEW_LINE( "std-err-stream-new-line" ),
+ /**
+ * This is the opcode "console-info-log". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:console-info-log:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "console-info-log"
+ * </ul>
+ */
BOOTERCODE_CONSOLE_INFO( "console-info-log" ),
+
+ /**
+ * This is the opcode "console-debug-log". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:console-debug-log:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "console-debug-log"
+ * </ul>
+ */
BOOTERCODE_CONSOLE_DEBUG( "console-debug-log" ),
+
+ /**
+ * This is the opcode "console-warning-log". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:console-warning-log:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "console-warning-log"
+ * </ul>
+ */
BOOTERCODE_CONSOLE_WARNING( "console-warning-log" ),
+
+ /**
+ * This is the opcode "console-error-log". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:console-error-log:RunMode:UTF-8:0xFFFFFFFF:line:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "console-error-log"
+ * </ul>
+ */
BOOTERCODE_CONSOLE_ERROR( "console-error-log" ),
+ /**
+ * This is the opcode "bye". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:bye:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "bye"
+ * </ul>
+ */
BOOTERCODE_BYE( "bye" ),
+
+ /**
+ * This is the opcode "stop-on-next-test". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:stop-on-next-test:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "stop-on-next-test"
+ * </ul>
+ */
BOOTERCODE_STOP_ON_NEXT_TEST( "stop-on-next-test" ),
+
+ /**
+ * This is the opcode "next-test". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:next-test:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "next-test"
+ * </ul>
+ */
BOOTERCODE_NEXT_TEST( "next-test" ),
+ /**
+ * This is the opcode "jvm-exit-error". The frame is composed of segments and the separator characters ':'
+ * <pre>
+ * :maven-surefire-event:jvm-exit-error:
+ * </pre>
+ * The constructor with one argument:
+ * <ul>
+ * <li>the opcode is "jvm-exit-error"
+ * </ul>
+ */
BOOTERCODE_JVM_EXIT_ERROR( "jvm-exit-error" );
- public static final String MAGIC_NUMBER = "maven-surefire-event";
-
- private static final Map<String, ForkedProcessEventType> EVENTS = events();
-
- private static Map<String, ForkedProcessEventType> events()
- {
- Map<String, ForkedProcessEventType> events = new ConcurrentHashMap<>();
- for ( ForkedProcessEventType event : values() )
- {
- events.put( event.getOpcode(), event );
- }
- return unmodifiableMap( events );
- }
-
private final String opcode;
+ private final byte[] opcodeBinary;
ForkedProcessEventType( String opcode )
{
this.opcode = opcode;
+ opcodeBinary = opcode.getBytes( US_ASCII );
}
public String getOpcode()
@@ -86,6 +296,11 @@ public enum ForkedProcessEventType
return opcode;
}
+ public byte[] getOpcodeBinary()
+ {
+ return opcodeBinary;
+ }
+
public boolean isSysPropCategory()
{
return this == BOOTERCODE_SYSPROPS;
@@ -130,9 +345,4 @@ public enum ForkedProcessEventType
{
return this == BOOTERCODE_JVM_EXIT_ERROR;
}
-
- public static ForkedProcessEventType byOpcode( @Nonnull String opcode )
- {
- return EVENTS.get( opcode );
- }
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/RunMode.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/RunMode.java
index 59aff6e..7329f9c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/RunMode.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/RunMode.java
@@ -19,10 +19,7 @@ package org.apache.maven.surefire.api.report;
* under the License.
*/
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static java.util.Collections.unmodifiableMap;
+import static java.nio.charset.StandardCharsets.US_ASCII;
/**
* Determines the purpose the provider started the tests. It can be either normal run or a kind of re-run type.
@@ -38,27 +35,22 @@ public enum RunMode
RERUN_TEST_AFTER_FAILURE( "rerun-test-after-failure" );
//todo add here RERUN_TESTSET, see https://github.com/apache/maven-surefire/pull/221
- public static final Map<String, RunMode> MODES = modes();
+ private final String runmode;
+ private final byte[] runmodeBinary;
- private static Map<String, RunMode> modes()
+ RunMode( String runmode )
{
- Map<String, RunMode> modes = new ConcurrentHashMap<>();
- for ( RunMode mode : values() )
- {
- modes.put( mode.geRunName(), mode );
- }
- return unmodifiableMap( modes );
+ this.runmode = runmode;
+ runmodeBinary = runmode.getBytes( US_ASCII );
}
- private final String runName;
-
- RunMode( String runName )
+ public String geRunmode()
{
- this.runName = runName;
+ return runmode;
}
- public String geRunName()
+ public byte[] getRunmodeBinary()
{
- return runName;
+ return runmodeBinary;
}
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
index 315d350..9d29495 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
@@ -77,7 +77,7 @@ public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDe
tokens.clear();
token.setLength( 0 );
FrameCompletion completion = null;
- for ( boolean frameStarted = false; !( endOfStream = channel.read( buffer ) == -1 ) ; completion = null )
+ for ( boolean frameStarted = false; !( endOfStream = channel.read( buffer ) == -1 ); completion = null )
{
buffer.flip();
char c = (char) buffer.get();
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
index 3cbc8eb..f8cb224 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
@@ -27,21 +27,23 @@ import org.apache.maven.surefire.api.report.ReportEntry;
import org.apache.maven.surefire.api.report.RunMode;
import org.apache.maven.surefire.api.report.SafeThrowable;
import org.apache.maven.surefire.api.report.StackTraceWriter;
-import org.apache.maven.surefire.shared.codec.binary.Base64;
import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
-import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.lang.Math.ceil;
+import static java.nio.CharBuffer.wrap;
import static java.util.Objects.requireNonNull;
+import static org.apache.maven.surefire.api.booter.Constants.DEFAULT_STREAM_ENCODING;
+import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER_BYTES;
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_BYE;
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_ERROR;
@@ -63,7 +65,6 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
-import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.MAGIC_NUMBER;
import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE;
@@ -74,11 +75,12 @@ import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAIL
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
+@SuppressWarnings( "checkstyle:linelength" )
public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEncoder
{
- private static final Base64 BASE64 = new Base64();
- private static final Charset STREAM_ENCODING = US_ASCII;
- private static final Charset STRING_ENCODING = UTF_8;
+ private static final byte[] INT_BINARY = new byte[] {0, 0, 0, 0};
+ private static final byte BOOLEAN_NON_NULL_OBJECT = (byte) 0xff;
+ private static final byte BOOLEAN_NULL_OBJECT = (byte) 0;
private final WritableBufferedByteChannel out;
private final RunMode runMode;
@@ -118,18 +120,27 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
public void onJvmExit()
{
onExit = true;
- encodeAndPrintEvent( new StringBuilder( "\n" ), true );
+ encodeAndPrintEvent( ByteBuffer.wrap( new byte[] {'\n'} ), true );
}
@Override
public void sendSystemProperties( Map<String, String> sysProps )
{
- for ( Entry<String, String> entry : sysProps.entrySet() )
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+ ByteBuffer result = null;
+ for ( Iterator<Entry<String, String>> it = sysProps.entrySet().iterator(); it.hasNext(); )
{
+ Entry<String, String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
- StringBuilder event = encode( BOOTERCODE_SYSPROPS, runMode, key, value );
- encodeAndPrintEvent( event, false );
+
+ int bufferLength = estimateBufferLength( BOOTERCODE_SYSPROPS, runMode, encoder, 0, key, value );
+ result = result != null && result.capacity() >= bufferLength ? result : ByteBuffer.allocate( bufferLength );
+ result.clear();
+ // :maven-surefire-event:sys-prop:rerun-test-after-failure:UTF-8:0000000000:<key>:0000000000:<value>:
+ encode( encoder, result, BOOTERCODE_SYSPROPS, runMode, key, value );
+ boolean sendImmediately = !it.hasNext();
+ encodeAndPrintEvent( result, sendImmediately );
}
}
@@ -185,36 +196,33 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
public void stdOut( String msg, boolean newLine )
{
ForkedProcessEventType event = newLine ? BOOTERCODE_STDOUT_NEW_LINE : BOOTERCODE_STDOUT;
- setOutErr( event.getOpcode(), msg );
+ setOutErr( event, msg );
}
@Override
public void stdErr( String msg, boolean newLine )
{
ForkedProcessEventType event = newLine ? BOOTERCODE_STDERR_NEW_LINE : BOOTERCODE_STDERR;
- setOutErr( event.getOpcode(), msg );
+ setOutErr( event, msg );
}
- private void setOutErr( String eventType, String message )
+ private void setOutErr( ForkedProcessEventType eventType, String message )
{
- String base64Message = toBase64( message );
- StringBuilder event = encodeMessage( eventType, runMode.geRunName(), base64Message );
- encodeAndPrintEvent( event, false );
+ ByteBuffer result = encodeMessage( eventType, runMode, message );
+ encodeAndPrintEvent( result, false );
}
@Override
- public void consoleInfoLog( String msg )
+ public void consoleInfoLog( String message )
{
- StringBuilder event = print( BOOTERCODE_CONSOLE_INFO.getOpcode(), msg );
- encodeAndPrintEvent( event, true );
+ ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_INFO, null, message );
+ encodeAndPrintEvent( result, true );
}
@Override
- public void consoleErrorLog( String msg )
+ public void consoleErrorLog( String message )
{
- StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), null );
- encode( encoded, msg, null, null );
- encodeAndPrintEvent( encoded, true );
+ consoleErrorLog( message, null );
}
@Override
@@ -224,11 +232,15 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
}
@Override
- public void consoleErrorLog( String msg, Throwable t )
+ public void consoleErrorLog( String message, Throwable t )
{
- StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), null );
- encode( encoded, msg, null, ConsoleLoggerUtils.toString( t ) );
- encodeAndPrintEvent( encoded, true );
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+ String stackTrace = t == null ? null : ConsoleLoggerUtils.toString( t );
+ int bufferMaxLength = estimateBufferLength( BOOTERCODE_CONSOLE_ERROR, null, encoder, 0, message, stackTrace );
+ ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
+ encodeHeader( encoder, result, BOOTERCODE_CONSOLE_ERROR, null );
+ encode( encoder, result, message, null, stackTrace );
+ encodeAndPrintEvent( result, true );
}
@Override
@@ -238,17 +250,17 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
}
@Override
- public void consoleDebugLog( String msg )
+ public void consoleDebugLog( String message )
{
- StringBuilder event = print( BOOTERCODE_CONSOLE_DEBUG.getOpcode(), msg );
- encodeAndPrintEvent( event, true );
+ ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_DEBUG, null, message );
+ encodeAndPrintEvent( result, true );
}
@Override
- public void consoleWarningLog( String msg )
+ public void consoleWarningLog( String message )
{
- StringBuilder event = print( BOOTERCODE_CONSOLE_WARNING.getOpcode(), msg );
- encodeAndPrintEvent( event, true );
+ ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_WARNING, null, message );
+ encodeAndPrintEvent( result, true );
}
@Override
@@ -275,51 +287,61 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
error( stackTraceWriter, trimStackTraces, BOOTERCODE_JVM_EXIT_ERROR, true );
}
- private void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces, ForkedProcessEventType event,
+ private void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces, ForkedProcessEventType eventType,
@SuppressWarnings( "SameParameterValue" ) boolean sendImmediately )
{
- StringBuilder encoded = encodeHeader( event.getOpcode(), null );
- encode( encoded, stackTraceWriter, trimStackTraces );
- encodeAndPrintEvent( encoded, sendImmediately );
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+ StackTrace stackTraceWrapper = new StackTrace( stackTraceWriter, trimStackTraces );
+ int bufferMaxLength = estimateBufferLength( eventType, null, encoder, 0,
+ stackTraceWrapper.message, stackTraceWrapper.smartTrimmedStackTrace, stackTraceWrapper.stackTrace );
+ ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
+
+ encodeHeader( encoder, result, eventType, null );
+ encode( encoder, result, stackTraceWrapper );
+ encodeAndPrintEvent( result, sendImmediately );
}
+ /**
+ * :maven-surefire-event:testset-starting:rerun-test-after-failure:UTF-8:0000000000:SourceName:0000000000:SourceText:0000000000:Name:0000000000:NameText:0000000000:Group:0000000000:Message:0000000000:ElapsedTime:0000000000:LocalizedMessage:0000000000:SmartTrimmedStackTrace:0000000000:toStackTrace( stw, trimStackTraces ):0000000000:
+ *
+ */
private void encode( ForkedProcessEventType operation, RunMode runMode, ReportEntry reportEntry,
boolean trimStackTraces, @SuppressWarnings( "SameParameterValue" ) boolean sendImmediately )
{
- StringBuilder event = encode( operation.getOpcode(), runMode.geRunName(), reportEntry, trimStackTraces );
- encodeAndPrintEvent( event, sendImmediately );
+ ByteBuffer result = encode( operation, runMode, reportEntry, trimStackTraces );
+ encodeAndPrintEvent( result, sendImmediately );
}
- private void encodeOpcode( ForkedProcessEventType operation, boolean sendImmediately )
+ private void encodeOpcode( ForkedProcessEventType eventType, boolean sendImmediately )
{
- StringBuilder event = encodeOpcode( operation.getOpcode(), null );
- encodeAndPrintEvent( event, sendImmediately );
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+ int bufferMaxLength = estimateBufferLength( eventType, null, null, 0 );
+ ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
+ encodeOpcode( encoder, result, eventType, null );
+ encodeAndPrintEvent( result, sendImmediately );
}
- private void encodeAndPrintEvent( StringBuilder event, boolean sendImmediately )
+ private void encodeAndPrintEvent( ByteBuffer frame, boolean sendImmediately )
{
final boolean wasInterrupted = Thread.interrupted();
try
{
- byte[] array = event.append( '\n' )
- .toString()
- .getBytes( STREAM_ENCODING );
-
- ByteBuffer bb = ByteBuffer.wrap( array );
-
if ( sendImmediately )
{
- out.write( bb );
+ out.write( frame );
}
else
{
- out.writeBuffered( bb );
+ out.writeBuffered( frame );
}
}
catch ( ClosedChannelException e )
{
if ( !onExit )
{
+ String event = new String( frame.array(), frame.arrayOffset() + frame.position(), frame.remaining(),
+ DEFAULT_STREAM_ENCODING );
+
DumpErrorSingleton.getSingleton()
.dumpException( e, "Channel closed while writing the event '" + event + "'." );
}
@@ -341,36 +363,27 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
}
}
- static StringBuilder encode( ForkedProcessEventType operation, RunMode runMode, String... args )
+ static void encode( CharsetEncoder encoder, ByteBuffer result,
+ ForkedProcessEventType operation, RunMode runMode, String... messages )
{
- StringBuilder encodedTo = encodeHeader( operation.getOpcode(), runMode.geRunName() );
-
- for ( int i = 0; i < args.length; )
+ encodeHeader( encoder, result, operation, runMode );
+ for ( String message : messages )
{
- String arg = args[i++];
- encodedTo.append( toBase64( arg ) )
- .append( ':' );
+ encodeString( encoder, result, message );
}
- return encodedTo;
}
- static void encode( StringBuilder encoded, StackTraceWriter stw, boolean trimStackTraces )
+ static void encode( CharsetEncoder encoder, ByteBuffer result, StackTrace stw )
{
- 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 );
+ encode( encoder, result, stw.message, stw.smartTrimmedStackTrace, stw.stackTrace );
}
- private static void encode( StringBuilder encoded, String message, String smartStackTrace, String stackTrace )
+ private static void encode( CharsetEncoder encoder, ByteBuffer result,
+ String message, String smartStackTrace, String stackTrace )
{
- encoded.append( toBase64( message ) )
- .append( ':' )
- .append( toBase64( smartStackTrace ) )
- .append( ':' )
- .append( toBase64( stackTrace ) )
- .append( ':' );
+ encodeString( encoder, result, message );
+ encodeString( encoder, result, smartStackTrace );
+ encodeString( encoder, result, stackTrace );
}
/**
@@ -386,60 +399,86 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
* <li>{@link ForkedProcessEventType#BOOTERCODE_TEST_ASSUMPTIONFAILURE}.</li>
* </ul>
*/
- static StringBuilder encode( String operation, String runMode, ReportEntry reportEntry, boolean trimStackTraces )
+ static ByteBuffer encode( ForkedProcessEventType operation, RunMode runMode, ReportEntry reportEntry,
+ boolean trimStackTraces )
{
- StringBuilder encodedTo = encodeHeader( operation, runMode )
- .append( toBase64( reportEntry.getSourceName() ) )
- .append( ':' )
- .append( toBase64( reportEntry.getSourceText() ) )
- .append( ':' )
- .append( toBase64( reportEntry.getName() ) )
- .append( ':' )
- .append( toBase64( reportEntry.getNameText() ) )
- .append( ':' )
- .append( toBase64( reportEntry.getGroup() ) )
- .append( ':' )
- .append( toBase64( reportEntry.getMessage() ) )
- .append( ':' )
- .append( reportEntry.getElapsed() == null ? "-" : reportEntry.getElapsed().toString() )
- .append( ':' );
+ StackTrace stackTraceWrapper = new StackTrace( reportEntry.getStackTraceWriter(), trimStackTraces );
+
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+
+ int bufferMaxLength = estimateBufferLength( operation, runMode, encoder, 1, reportEntry.getSourceName(),
+ reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
+ reportEntry.getMessage(), stackTraceWrapper.message, stackTraceWrapper.smartTrimmedStackTrace,
+ stackTraceWrapper.stackTrace );
+
+ ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
- encode( encodedTo, reportEntry.getStackTraceWriter(), trimStackTraces );
+ encodeHeader( encoder, result, operation, runMode );
- return encodedTo;
+ encodeString( encoder, result, reportEntry.getSourceName() );
+ encodeString( encoder, result, reportEntry.getSourceText() );
+ encodeString( encoder, result, reportEntry.getName() );
+ encodeString( encoder, result, reportEntry.getNameText() );
+ encodeString( encoder, result, reportEntry.getGroup() );
+ encodeString( encoder, result, reportEntry.getMessage() );
+ encodeInteger( encoder, result, reportEntry.getElapsed() );
+
+ encode( encoder, result, stackTraceWrapper );
+
+ return result;
}
- /**
- * Used in {@link #consoleInfoLog(String)}, {@link #consoleErrorLog(String)}, {@link #consoleDebugLog(String)},
- * {@link #consoleWarningLog(String)} and private methods extending the buffer.
- */
- StringBuilder print( String operation, String... msgs )
+ static ByteBuffer encodeMessage( ForkedProcessEventType eventType, RunMode runMode, String message )
{
- String[] encodedMsgs = new String[msgs.length];
- for ( int i = 0; i < encodedMsgs.length; i++ )
- {
- String msg = msgs[i];
- encodedMsgs[i] = toBase64( msg );
- }
- return encodeMessage( operation, null, encodedMsgs );
+ CharsetEncoder encoder = DEFAULT_STREAM_ENCODING.newEncoder();
+ int bufferMaxLength = estimateBufferLength( eventType, runMode, encoder, 0, message );
+ ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
+ encodeHeader( encoder, result, eventType, runMode );
+ encodeString( encoder, result, message );
+ return result;
}
- static StringBuilder encodeMessage( String operation, String runMode, String... encodedMsgs )
+ private static void encodeString( CharsetEncoder encoder, ByteBuffer result, String string )
{
- StringBuilder builder = encodeHeader( operation, runMode );
- for ( String encodedMsg : encodedMsgs )
- {
- builder.append( encodedMsg ).append( ':' );
+ String nonNullString = nonNull( string );
+
+ int counterPosition = result.position();
+
+ result.put( INT_BINARY ).put( (byte) ':' );
+
+ int msgStart = result.position();
+ encoder.encode( wrap( nonNullString ), result, true );
+ int msgEnd = result.position();
+ int encodedMsgSize = msgEnd - msgStart;
+ result.putInt( counterPosition, encodedMsgSize );
+ result.position( msgEnd );
+
+ result.put( (byte) ':' );
+ }
+
+ private static void encodeInteger( CharsetEncoder encoder, ByteBuffer result, Integer i )
+ {
+ if ( i == null )
+ {
+ result.put( BOOLEAN_NULL_OBJECT );
+ }
+ else
+ {
+ result.put( BOOLEAN_NON_NULL_OBJECT ).putInt( i );
}
- return builder;
+ result.put( (byte) ':' );
}
- static StringBuilder encodeHeader( String operation, String runMode )
+ static void encodeHeader( CharsetEncoder encoder, ByteBuffer result, ForkedProcessEventType operation,
+ RunMode runMode )
{
- return encodeOpcode( operation, runMode )
- .append( STRING_ENCODING.name() )
- .append( ':' );
+ encodeOpcode( encoder, result, operation, runMode );
+ String charsetName = encoder.charset().name();
+ result.put( (byte) charsetName.length() );
+ result.put( (byte) ':' );
+ encoder.encode( wrap( charsetName ), result, true );
+ result.put( (byte) ':' );
}
/**
@@ -448,27 +487,91 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
*
* @param operation opcode
* @param runMode run mode
- * @return encoded event
*/
- static StringBuilder encodeOpcode( String operation, String runMode )
- {
- StringBuilder s = new StringBuilder( 128 )
- .append( ':' )
- .append( MAGIC_NUMBER )
- .append( ':' )
- .append( operation )
- .append( ':' );
-
- return runMode == null ? s : s.append( runMode ).append( ':' );
+ static void encodeOpcode( CharsetEncoder encoder, ByteBuffer result, ForkedProcessEventType operation,
+ RunMode runMode )
+ {
+ result.put( (byte) ':' );
+ result.put( MAGIC_NUMBER_BYTES );
+ result.put( (byte) ':' );
+ byte[] opcode = operation.getOpcodeBinary();
+ result.put( (byte) opcode.length );
+ result.put( (byte) ':' );
+ result.put( opcode );
+ result.put( (byte) ':' );
+
+ if ( runMode != null )
+ {
+ byte[] runmode = runMode.getRunmodeBinary();
+ result.put( (byte) runmode.length );
+ result.put( (byte) ':' );
+ result.put( runmode );
+ result.put( (byte) ':' );
+ }
}
private static String toStackTrace( StackTraceWriter stw, boolean trimStackTraces )
{
+ if ( stw == null )
+ {
+ return null;
+ }
+
return trimStackTraces ? stw.writeTrimmedTraceToString() : stw.writeTraceToString();
}
- static String toBase64( String msg )
+ static String nonNull( String msg )
{
- return msg == null ? "-" : new String( BASE64.encode( msg.getBytes( STRING_ENCODING ) ), STREAM_ENCODING );
+ return msg == null ? "\u0000" : msg;
+ }
+
+ static int estimateBufferLength( ForkedProcessEventType eventType, RunMode runMode, CharsetEncoder encoder,
+ int integersCounter, String... strings )
+ {
+ assert !( encoder == null && strings.length != 0 );
+
+ // one delimiter character ':' + <string> + one delimiter character ':' +
+ // one byte + one delimiter character ':' + <string> + one delimiter character ':'
+ int lengthOfMetadata = 1 + MAGIC_NUMBER_BYTES.length + 1 + 1 + 1 + eventType.getOpcode().length() + 1;
+
+ if ( runMode != null )
+ {
+ // one byte of length + one delimiter character ':' + <string> + one delimiter character ':'
+ lengthOfMetadata += 1 + 1 + runMode.geRunmode().length() + 1;
+ }
+
+ if ( encoder != null )
+ {
+ // one byte of length + one delimiter character ':' + <string> + one delimiter character ':'
+ lengthOfMetadata += 1 + 1 + encoder.charset().name().length() + 1;
+ }
+
+ // one byte (0x00 if NULL) + 4 bytes for integer + one delimiter character ':'
+ int lengthOfData = ( 1 + 4 + 1 ) * integersCounter;
+
+ for ( String string : strings )
+ {
+ String s = string == null ? "\u0000" : string;
+ // 4 bytes of string length + one delimiter character ':' + <string> + one delimiter character ':'
+ lengthOfData += 4 + 1 + (int) ceil( encoder.maxBytesPerChar() * s.length() ) + 1;
+ }
+
+
+ return lengthOfMetadata + lengthOfData;
+ }
+
+ private static final class StackTrace
+ {
+ final String message;
+ final String smartTrimmedStackTrace;
+ final String stackTrace;
+
+ StackTrace( StackTraceWriter stackTraceWriter, boolean trimStackTraces )
+ {
+ SafeThrowable throwable = stackTraceWriter == null ? null : stackTraceWriter.getThrowable();
+ message = throwable == null ? null : throwable.getLocalizedMessage();
+ smartTrimmedStackTrace = stackTraceWriter == null ? null : stackTraceWriter.smartTrimmedStackTrace();
+ stackTrace = stackTraceWriter == null ? null : toStackTrace( stackTraceWriter, trimStackTraces );
+ }
}
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
index 4e51318..7f72ba2 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.booter.spi;
* under the License.
*/
+import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
import org.apache.maven.surefire.api.report.ReportEntry;
import org.apache.maven.surefire.api.report.SafeThrowable;
import org.apache.maven.surefire.api.report.StackTraceWriter;
@@ -33,20 +34,40 @@ import java.io.PrintStream;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
import java.util.Map;
+import java.util.Map.Entry;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.copyOfRange;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_JVM_EXIT_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
+import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
-import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encode;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeHeader;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeMessage;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeOpcode;
-import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.toBase64;
-import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_SYSPROPS;
-import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.MAGIC_NUMBER;
-import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.estimateBufferLength;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -57,109 +78,109 @@ import static org.mockito.Mockito.when;
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 3.0.0-M4
*/
+@SuppressWarnings( { "checkstyle:linelength", "checkstyle:magicnumber" } )
public class LegacyMasterProcessChannelEncoderTest
{
private static final int ELAPSED_TIME = 102;
+ private static final byte[] ELAPSED_TIME_HEXA = new byte[] {0, 0, 0, 0x66};
@Test
- public void shouldBeFailSafe()
+ public void shouldComputeStreamPreemptiveLength()
{
- assertThat( toBase64( null ) ).isEqualTo( "-" );
- assertThat( toBase64( "" ) ).isEqualTo( "" );
- }
+ CharsetEncoder encoder = UTF_8.newEncoder();
- @Test
- public void shouldHaveSystemProperty()
- {
- StringBuilder actualEncoded = encode( BOOTERCODE_SYSPROPS, NORMAL_RUN, "arg1", "arg2" );
- String expected = ':' + MAGIC_NUMBER + ':' + BOOTERCODE_SYSPROPS.getOpcode()
- + ":normal-run:UTF-8:YXJnMQ==:YXJnMg==:";
+ // :maven-surefire-event:8:sys-prop:10:normal-run:5:UTF-8:0001:kkk:0001:vvv:
+ assertThat( estimateBufferLength( BOOTERCODE_SYSPROPS, NORMAL_RUN, encoder, 0, "k", "v" ) )
+ .isEqualTo( 72 );
- assertThat( actualEncoded.toString() )
- .isEqualTo( expected );
- }
+ // :maven-surefire-event:16:testset-starting:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TESTSET_STARTING, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 149 );
- @Test
- public void safeThrowableShouldBeEncoded()
- {
- final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
+ // :maven-surefire-event:17:testset-completed:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TESTSET_COMPLETED, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 150 );
- final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
+ // :maven-surefire-event:13:test-starting:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_STARTING, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 146 );
- final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
+ // :maven-surefire-event:14:test-succeeded:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_SUCCEEDED, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 147 );
- final String trimmedStackTrace = "trace line 1\ntrace line 2";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
+ // :maven-surefire-event:11:test-failed:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_FAILED, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 144 );
- 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 );
+ // :maven-surefire-event:12:test-skipped:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_SKIPPED, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 145 );
- 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 + ":" );
- }
+ // :maven-surefire-event:10:test-error:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_ERROR, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 143 );
- @Test
- public void emptySafeThrowable()
- {
- SafeThrowable safeThrowable = new SafeThrowable( new Exception( "" ) );
+ // :maven-surefire-event:23:test-assumption-failure:10:normal-run:5:UTF-8:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:0001:sss:X0001:0001:sss:0001:sss:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_TEST_ASSUMPTIONFAILURE, NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+ .isEqualTo( 156 );
- StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
- when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
- when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "" );
- when( stackTraceWriter.writeTraceToString() ).thenReturn( "" );
+ // :maven-surefire-event:14:std-out-stream:10:normal-run:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_STDOUT, NORMAL_RUN, encoder, 0, "s" ) )
+ .isEqualTo( 69 );
- StringBuilder encoded = new StringBuilder();
- encode( encoded, stackTraceWriter, false );
+ // :maven-surefire-event:23:std-out-stream-new-line:10:normal-run:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_STDOUT_NEW_LINE, NORMAL_RUN, encoder, 0, "s" ) )
+ .isEqualTo( 78 );
- assertThat( encoded.toString() )
- .isEqualTo( ":::" );
- }
+ // :maven-surefire-event:14:std-err-stream:10:normal-run:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_STDERR, NORMAL_RUN, encoder, 0, "s" ) )
+ .isEqualTo( 69 );
- @Test
- public void nullSafeThrowable()
- {
- SafeThrowable safeThrowable = new SafeThrowable( new Exception() );
+ // :maven-surefire-event:23:std-err-stream-new-line:10:normal-run:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_STDERR_NEW_LINE, NORMAL_RUN, encoder, 0, "s" ) )
+ .isEqualTo( 78 );
- StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
- when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ // :maven-surefire-event:16:console-info-log:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_CONSOLE_INFO, null, encoder, 0, "s" ) )
+ .isEqualTo( 58 );
+
+ // :maven-surefire-event:17:console-debug-log:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_CONSOLE_DEBUG, null, encoder, 0, "s" ) )
+ .isEqualTo( 59 );
+
+ // :maven-surefire-event:19:console-warning-log:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_CONSOLE_WARNING, null, encoder, 0, "s" ) )
+ .isEqualTo( 61 );
+
+ // :maven-surefire-event:17:console-error-log:5:UTF-8:0001:sss:
+ assertThat( estimateBufferLength( BOOTERCODE_CONSOLE_ERROR, null, encoder, 0, "s" ) )
+ .isEqualTo( 59 );
+
+ // :maven-surefire-event:3:bye:
+ assertThat( estimateBufferLength( BOOTERCODE_BYE, null, null, 0 ) )
+ .isEqualTo( 28 );
- StringBuilder encoded = new StringBuilder();
- encode( encoded, stackTraceWriter, false );
+ // :maven-surefire-event:17:stop-on-next-test:
+ assertThat( estimateBufferLength( BOOTERCODE_STOP_ON_NEXT_TEST, null, null, 0 ) )
+ .isEqualTo( 42 );
- assertThat( encoded.toString() )
- .isEqualTo( "-:-:-:" );
+ // :maven-surefire-event:9:next-test:
+ assertThat( estimateBufferLength( BOOTERCODE_NEXT_TEST, null, null, 0 ) )
+ .isEqualTo( 34 );
+
+ // :maven-surefire-event:14:jvm-exit-error:
+ assertThat( estimateBufferLength( BOOTERCODE_JVM_EXIT_ERROR, null, null, 0 ) )
+ .isEqualTo( 39 );
}
@Test
public void reportEntry() throws IOException
{
final String exceptionMessage = "msg";
- final String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
final String smartStackTrace = "MyTest:86 >> Error";
- final String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
final String stackTrace = "trace line 1\ntrace line 2";
- final String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
final String trimmedStackTrace = "trace line 1\ntrace line 2";
- final String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -168,7 +189,6 @@ public class LegacyMasterProcessChannelEncoderTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
-
ReportEntry reportEntry = mock( ReportEntry.class );
when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
when( reportEntry.getGroup() ).thenReturn( "this group" );
@@ -178,140 +198,228 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
- StringBuilder encode = encode( "X", "normal-run", reportEntry, false );
- assertThat( encode.toString() )
- .isEqualTo( ":maven-surefire-event:X:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
-
- encode = encode( "X", "normal-run", reportEntry, true );
- assertThat( encode.toString() )
- .isEqualTo( ":maven-surefire-event:X:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace
- + ":"
- );
+ ByteBuffer encoded = encode( BOOTERCODE_TEST_ERROR, NORMAL_RUN, reportEntry, false );
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":test-error:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ encoded.flip();
+
+ assertThat( toArray( encoded ) )
+ .isEqualTo( expectedFrame.toByteArray() );
+
+ encoded = encode( BOOTERCODE_TEST_ERROR, NORMAL_RUN, reportEntry, true );
+ expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":test-error:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( trimmedStackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ encoded.flip();
+
+ assertThat( toArray( encoded ) )
+ .isEqualTo( expectedFrame.toByteArray() );
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetStarting( reportEntry, true );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:testset-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 16 );
+ expectedFrame.write( ":testset-starting:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( trimmedStackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
out = Stream.newStream();
encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetStarting( reportEntry, false );
- printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:testset-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 16 );
+ expectedFrame.write( ":testset-starting:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testSetCompleted() throws IOException
{
String exceptionMessage = "msg";
- String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -329,57 +437,68 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetCompleted( reportEntry, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:testset-completed:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 17 );
+ expectedFrame.write( ":testset-completed:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testStarting() throws IOException
{
String exceptionMessage = "msg";
- String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -397,57 +516,69 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testStarting( reportEntry, true );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-starting:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 13 );
+ expectedFrame.write( ":test-starting:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testSuccess() throws IOException
{
String exceptionMessage = "msg";
- String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -465,57 +596,68 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSucceeded( reportEntry, true );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-succeeded:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedTrimmedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 14 );
+ expectedFrame.write( ":test-succeeded:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testFailed() throws IOException
{
String exceptionMessage = "msg";
- String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
-
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -533,56 +675,67 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testFailed( reportEntry, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-failed:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 11 );
+ expectedFrame.write( ":test-failed:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testSkipped() throws IOException
{
- String encodedExceptionMsg = "-";
-
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
-
String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
SafeThrowable safeThrowable = new SafeThrowable( new Exception() );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -600,55 +753,67 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSkipped( reportEntry, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-skipped:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 12 );
+ expectedFrame.write( ":test-skipped:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xFF );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getStackTraceWriter().smartTrimmedStackTrace().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testError() throws IOException
{
- String encodedExceptionMsg = "-";
-
- String encodedSmartStackTrace = "-";
-
String stackTrace = "trace line 1\ntrace line 2";
- String encodedStackTrace = encodeBase64String( toArray( UTF_8.encode( stackTrace ) ) );
- String trimmedStackTrace = "trace line 1\ntrace line 2";
- String encodedTrimmedStackTrace = encodeBase64String( toArray( UTF_8.encode( trimmedStackTrace ) ) );
+ String trimmedStackTrace = "trace line 1";
SafeThrowable safeThrowable = new SafeThrowable( new Exception() );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -666,53 +831,66 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
-
encoder.testError( reportEntry, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-error:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + ELAPSED_TIME
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":test-error:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0xff );
+ expectedFrame.write( ELAPSED_TIME_HEXA );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 25} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
public void testAssumptionFailure() throws IOException
{
String exceptionMessage = "msg";
- String encodedExceptionMsg = encodeBase64String( toArray( UTF_8.encode( exceptionMessage ) ) );
String smartStackTrace = "MyTest:86 >> Error";
- String encodedSmartStackTrace = encodeBase64String( toArray( UTF_8.encode( smartStackTrace ) ) );
-
- String encodedStackTrace = "-";
SafeThrowable safeThrowable = new SafeThrowable( new Exception( exceptionMessage ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
@@ -730,106 +908,131 @@ public class LegacyMasterProcessChannelEncoderTest
when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
- String encodedSourceName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getSourceName() ) ) );
- String encodedName = encodeBase64String( toArray( UTF_8.encode( reportEntry.getName() ) ) );
- String encodedGroup = encodeBase64String( toArray( UTF_8.encode( reportEntry.getGroup() ) ) );
- String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
-
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testAssumptionFailure( reportEntry, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:test-assumption-failure:normal-run:UTF-8:"
- + encodedSourceName
- + ":"
- + "-"
- + ":"
- + encodedName
- + ":"
- + "-"
- + ":"
- + encodedGroup
- + ":"
- + encodedMessage
- + ":"
- + "-"
- + ":"
-
- + encodedExceptionMsg
- + ":"
- + encodedSmartStackTrace
- + ":"
- + encodedStackTrace
- + ":"
- );
- assertThat( printedLines.readLine() ).isNull();
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 23 );
+ expectedFrame.write( ":test-assumption-failure:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 10 );
+ expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+ expectedFrame.write( (byte) 5 );
+ expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getSourceName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 7} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getName().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 10} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getGroup().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 12} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( reportEntry.getMessage().getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 3} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( exceptionMessage.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 18} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( smartStackTrace.getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( new byte[] {0, 0, 0, 1} );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
- public void testBye() throws IOException
+ public void testBye()
{
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.bye();
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:bye:" );
- assertThat( printedLines.readLine() ).isNull();
+
+ String encoded = new String( out.toByteArray(), UTF_8 );
+
+ assertThat( encoded )
+ .isEqualTo( ":maven-surefire-event:\u0003:bye:" );
}
@Test
- public void testStopOnNextTest() throws IOException
+ public void testStopOnNextTest()
{
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.stopOnNextTest();
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:stop-on-next-test:" );
- assertThat( printedLines.readLine() ).isNull();
+
+ String encoded = new String( out.toByteArray(), UTF_8 );
+ assertThat( encoded )
+ .isEqualTo( ":maven-surefire-event:\u0011:stop-on-next-test:" );
}
@Test
- public void testAcquireNextTest() throws IOException
+ public void testAcquireNextTest()
{
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.acquireNextTest();
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( ":maven-surefire-event:next-test:" );
- assertThat( printedLines.readLine() ).isNull();
+
+ String encoded = new String( out.toByteArray(), UTF_8 );
+ assertThat( encoded )
+ .isEqualTo( ":maven-surefire-event:\u0009:next-test:" );
}
@Test
public void testSendOpcode()
{
- StringBuilder encoded = encodeOpcode( "some-opcode", "normal-run" );
- assertThat( encoded.toString() )
- .isEqualTo( ":maven-surefire-event:some-opcode:normal-run:" );
-
- encoded = encodeHeader( "some-opcode", "normal-run" );
- assertThat( encoded.toString() )
- .isEqualTo( ":maven-surefire-event:some-opcode:normal-run:UTF-8:" );
-
- encoded = encodeMessage( "some-opcode", "normal-run", "msg" );
- assertThat( encoded.toString() )
- .isEqualTo( ":maven-surefire-event:some-opcode:normal-run:UTF-8:msg:" );
-
- Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
- encoded = encoder.print( "some-opcode", "msg" );
- assertThat( encoded.toString() )
- .isEqualTo( ":maven-surefire-event:some-opcode:UTF-8:bXNn:" );
-
- encoded = encoder.print( "some-opcode", new String[] { null } );
- assertThat( encoded.toString() )
- .isEqualTo( ":maven-surefire-event:some-opcode:UTF-8:-:" );
+ CharsetEncoder encoder = UTF_8.newEncoder();
+ ByteBuffer result = ByteBuffer.allocate( 128 );
+ encodeOpcode( encoder, result, BOOTERCODE_TEST_ERROR, NORMAL_RUN );
+ assertThat( toString( result ) )
+ .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:" );
+
+ result = ByteBuffer.allocate( 1024 );
+ encodeHeader( encoder, result, BOOTERCODE_TEST_ERROR, NORMAL_RUN );
+ assertThat( toString( result ) )
+ .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:"
+ + (char) 5 + ":UTF-8:" );
+
+ result = encodeMessage( BOOTERCODE_TEST_ERROR, NORMAL_RUN, "msg" );
+ assertThat( toString( result ) )
+ .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:"
+ + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:" );
+
+ Channel channel = new Channel();
+ new LegacyMasterProcessChannelEncoder( channel ).stdOut( "msg", false );
+ assertThat( toString( channel.src ) )
+ .isEqualTo( ":maven-surefire-event:" + (char) 14 + ":std-out-stream:" + (char) 10 + ":normal-run:"
+ + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:" );
+
+ channel = new Channel();
+ new LegacyMasterProcessChannelEncoder( channel ).stdErr( null, false );
+ assertThat( toString( channel.src ) )
+ .isEqualTo( ":maven-surefire-event:" + (char) 14 + ":std-err-stream:" + (char) 10 + ":normal-run:"
+ + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0001:\u0000:" );
}
@Test
@@ -842,10 +1045,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encoded = new String( out.toByteArray(), UTF_8 );
- String expected = ":maven-surefire-event:console-info-log:UTF-8:"
- + encodeBase64String( toArray( UTF_8.encode( "msg" ) ) )
- + ":"
- + "\n";
+ String expected = ":maven-surefire-event:\u0010:console-info-log:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
assertThat( encoded )
.isEqualTo( expected );
@@ -861,9 +1061,10 @@ public class LegacyMasterProcessChannelEncoderTest
String encoded = new String( out.toByteArray(), UTF_8 );
- String expected = ":maven-surefire-event:console-error-log:UTF-8:"
- + encodeBase64String( toArray( UTF_8.encode( "msg" ) ) )
- + ":-:-:\n";
+ String expected = ":maven-surefire-event:\u0011:console-error-log:\u0005:UTF-8:"
+ + "\u0000\u0000\u0000\u0003:msg:"
+ + "\u0000\u0000\u0000\u0001:\u0000:"
+ + "\u0000\u0000\u0000\u0001:\u0000:";
assertThat( encoded )
.isEqualTo( expected );
@@ -875,11 +1076,36 @@ public class LegacyMasterProcessChannelEncoderTest
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
- encoder.consoleErrorLog( new Exception( "msg" ) );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .startsWith( ":maven-surefire-event:console-error-log:UTF-8:bXNn:-:" );
- assertThat( printedLines.readLine() ).isNull();
+ Exception e = new Exception( "msg" );
+ encoder.consoleErrorLog( e );
+ String stackTrace = ConsoleLoggerUtils.toString( e );
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:\u0011:console-error-log:\u0005:UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 3 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( "msg".getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 1 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ byte[] stackTraceBytes = stackTrace.getBytes( UTF_8 );
+ int[] stackTraceLength = toBytes( stackTraceBytes.length );
+ expectedFrame.write( stackTraceLength[0] );
+ expectedFrame.write( stackTraceLength[1] );
+ expectedFrame.write( stackTraceLength[2] );
+ expectedFrame.write( stackTraceLength[3] );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTraceBytes );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
@@ -888,15 +1114,40 @@ public class LegacyMasterProcessChannelEncoderTest
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
- encoder.consoleErrorLog( "msg2", new Exception( "msg" ) );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .startsWith( ":maven-surefire-event:console-error-log:UTF-8:bXNnMg==:-:" );
- assertThat( printedLines.readLine() ).isNull();
+ Exception e = new Exception( "msg" );
+ encoder.consoleErrorLog( "msg2", e );
+ String stackTrace = ConsoleLoggerUtils.toString( e );
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:\u0011:console-error-log:\u0005:UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 4 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( "msg2".getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 0 );
+ expectedFrame.write( 1 );
+ expectedFrame.write( ':' );
+ expectedFrame.write( 0 );
+ expectedFrame.write( ':' );
+ byte[] stackTraceBytes = stackTrace.getBytes( UTF_8 );
+ int[] stackTraceLength = toBytes( stackTraceBytes.length );
+ expectedFrame.write( stackTraceLength[0] );
+ expectedFrame.write( stackTraceLength[1] );
+ expectedFrame.write( stackTraceLength[2] );
+ expectedFrame.write( stackTraceLength[3] );
+ expectedFrame.write( ':' );
+ expectedFrame.write( stackTraceBytes );
+ expectedFrame.write( ':' );
+ assertThat( out.toByteArray() )
+ .isEqualTo( expectedFrame.toByteArray() );
}
@Test
- public void testConsoleErrorLog3() throws IOException
+ public void testConsoleErrorLog3()
{
Stream out = Stream.newStream();
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
@@ -908,10 +1159,9 @@ public class LegacyMasterProcessChannelEncoderTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
encoder.consoleErrorLog( stackTraceWriter, true );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .startsWith( ":maven-surefire-event:console-error-log:UTF-8:MQ==:Mg==:NA==:" );
- assertThat( printedLines.readLine() ).isNull();
+ String encoded = new String( out.toByteArray(), UTF_8 );
+ assertThat( encoded )
+ .startsWith( ":maven-surefire-event:\u0011:console-error-log:\u0005:UTF-8:\u0000\u0000\u0000\u0001:1:\u0000\u0000\u0000\u0001:2:\u0000\u0000\u0000\u0001:4:" );
}
@Test
@@ -924,10 +1174,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encoded = new String( out.toByteArray(), UTF_8 );
- String expected = ":maven-surefire-event:console-debug-log:UTF-8:"
- + encodeBase64String( toArray( UTF_8.encode( "msg" ) ) )
- + ":"
- + "\n";
+ String expected = ":maven-surefire-event:\u0011:console-debug-log:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
assertThat( encoded )
.isEqualTo( expected );
@@ -943,10 +1190,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encoded = new String( out.toByteArray(), UTF_8 );
- String expected = ":maven-surefire-event:console-warning-log:UTF-8:"
- + encodeBase64String( toArray( UTF_8.encode( "msg" ) ) )
- + ":"
- + "\n";
+ String expected = ":maven-surefire-event:\u0013:console-warning-log:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
assertThat( encoded )
.isEqualTo( expected );
@@ -962,13 +1206,11 @@ public class LegacyMasterProcessChannelEncoderTest
encoder.stdOut( "msg", false );
channel.close();
- String expected = ":maven-surefire-event:std-out-stream:normal-run:UTF-8:bXNn:";
+ String expected = ":maven-surefire-event:\u000e:std-out-stream:"
+ + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
.isEqualTo( expected );
- assertThat( printedLines.readLine() )
- .isNull();
}
@Test
@@ -981,13 +1223,11 @@ public class LegacyMasterProcessChannelEncoderTest
encoder.stdOut( "msg", true );
channel.close();
- String expected = ":maven-surefire-event:std-out-stream-new-line:normal-run:UTF-8:bXNn:";
+ String expected = ":maven-surefire-event:\u0017:std-out-stream-new-line:"
+ + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
.isEqualTo( expected );
- assertThat( printedLines.readLine() )
- .isNull();
}
@Test
@@ -1000,13 +1240,11 @@ public class LegacyMasterProcessChannelEncoderTest
encoder.stdErr( "msg", false );
channel.close();
- String expected = ":maven-surefire-event:std-err-stream:normal-run:UTF-8:bXNn:";
+ String expected = ":maven-surefire-event:\u000e:std-err-stream:"
+ + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
.isEqualTo( expected );
- assertThat( printedLines.readLine() )
- .isNull();
}
@Test
@@ -1019,43 +1257,50 @@ public class LegacyMasterProcessChannelEncoderTest
encoder.stdErr( "msg", true );
channel.close();
- String expected = ":maven-surefire-event:std-err-stream-new-line:normal-run:UTF-8:bXNn:";
+ String expected = ":maven-surefire-event:\u0017:std-err-stream-new-line:"
+ + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
.isEqualTo( expected );
- assertThat( printedLines.readLine() )
- .isNull();
}
@Test
@SuppressWarnings( "checkstyle:innerassignment" )
public void shouldCountSameNumberOfSystemProperties() throws IOException
{
- Stream out = Stream.newStream();
- WritableBufferedByteChannel channel = newBufferedChannel( out );
+ Stream stream = Stream.newStream();
+ WritableBufferedByteChannel channel = newBufferedChannel( stream );
LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
Map<String, String> sysProps = ObjectUtils.systemProps();
- int expectedSize = sysProps.size();
encoder.sendSystemProperties( sysProps );
channel.close();
- LineNumberReader printedLines = out.newReader( UTF_8 );
-
- int size = 0;
- for ( String line; ( line = printedLines.readLine() ) != null; size++ )
+ for ( Entry<String, String> entry : sysProps.entrySet() )
{
- assertThat( line )
- .startsWith( ":maven-surefire-event:sys-prop:normal-run:UTF-8:" );
+ int[] k = toBytes( entry.getKey().length() );
+ int[] v = toBytes( entry.getValue() == null ? 1 : entry.getValue().getBytes( UTF_8 ).length );
+ ByteArrayOutputStream expectedFrame = new ByteArrayOutputStream();
+ expectedFrame.write( ":maven-surefire-event:sys-prop:normal-run:UTF-8:".getBytes( UTF_8 ) );
+ expectedFrame.write( k[0] );
+ expectedFrame.write( k[1] );
+ expectedFrame.write( k[2] );
+ expectedFrame.write( k[3] );
+ expectedFrame.write( ':' );
+ expectedFrame.write( v[0] );
+ expectedFrame.write( v[1] );
+ expectedFrame.write( v[2] );
+ expectedFrame.write( v[3] );
+ expectedFrame.write( ':' );
+ expectedFrame.write( ( entry.getValue() == null ? "\u0000" : entry.getValue() ).getBytes( UTF_8 ) );
+ expectedFrame.write( ':' );
+ assertThat( stream.toByteArray() )
+ .contains( expectedFrame.toByteArray() );
}
-
- assertThat( size )
- .isEqualTo( expectedSize );
}
@Test
- public void shouldHandleExit() throws IOException
+ public void shouldHandleExit()
{
Stream out = Stream.newStream();
@@ -1067,13 +1312,12 @@ public class LegacyMasterProcessChannelEncoderTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
encoder.sendExitError( stackTraceWriter, false );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .startsWith( ":maven-surefire-event:jvm-exit-error:UTF-8:MQ==:Mg==:Mw==:" );
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
+ .startsWith( ":maven-surefire-event:\u000e:jvm-exit-error:\u0005:UTF-8:\u0000\u0000\u0000\u0001:1:\u0000\u0000\u0000\u0001:2:\u0000\u0000\u0000\u0001:3:" );
}
@Test
- public void shouldHandleExitWithTrimmedTrace() throws IOException
+ public void shouldHandleExitWithTrimmedTrace()
{
Stream out = Stream.newStream();
@@ -1085,9 +1329,8 @@ public class LegacyMasterProcessChannelEncoderTest
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
encoder.sendExitError( stackTraceWriter, true );
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .startsWith( ":maven-surefire-event:jvm-exit-error:UTF-8:MQ==:Mg==:NA==:" );
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
+ .startsWith( ":maven-surefire-event:\u000e:jvm-exit-error:\u0005:UTF-8:\u0000\u0000\u0000\u0001:1:\u0000\u0000\u0000\u0001:2:\u0000\u0000\u0000\u0001:4:" );
}
@Test
@@ -1110,13 +1353,9 @@ public class LegacyMasterProcessChannelEncoderTest
.isTrue();
}
- String expected = ":maven-surefire-event:std-out-stream:normal-run:UTF-8:bXNn:";
-
- LineNumberReader printedLines = out.newReader( UTF_8 );
- assertThat( printedLines.readLine() )
- .isEqualTo( expected );
- assertThat( printedLines.readLine() )
- .isNull();
+ assertThat( new String( out.toByteArray(), UTF_8 ) )
+ .isEqualTo( ":maven-surefire-event:\u000e:std-out-stream:"
+ + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:" );
}
private static class Stream extends PrintStream
@@ -1150,4 +1389,51 @@ public class LegacyMasterProcessChannelEncoderTest
return copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
}
+ private static String toString( ByteBuffer frame )
+ {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ frame.flip();
+ os.write( frame.array(), frame.arrayOffset() + frame.position(), frame.remaining() );
+ return new String( os.toByteArray(), UTF_8 );
+ }
+
+ private static int[] toBytes( int i )
+ {
+ int[] result = new int[4];
+ result[0] = 0xff & ( i >> 24 );
+ result[1] = 0xff & ( i >> 16 );
+ result[2] = 0xff & ( i >> 8 );
+ result[3] = 0xff & i;
+ return result;
+ }
+
+ private static final class Channel implements WritableBufferedByteChannel
+ {
+ ByteBuffer src;
+
+ @Override
+ public void writeBuffered( ByteBuffer src ) throws IOException
+ {
+ this.src = src;
+ }
+
+ @Override
+ public int write( ByteBuffer src ) throws IOException
+ {
+ this.src = src;
+ return 0;
+ }
+
+ @Override
+ public boolean isOpen()
+ {
+ return false;
+ }
+
+ @Override
+ public void close()
+ {
+
+ }
+ }
}
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeArguments.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeArguments.java
index 53da2bd..4ab6cc3 100644
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeArguments.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ForkNodeArguments.java
@@ -47,6 +47,9 @@ public interface ForkNodeArguments
@Nonnull
File dumpStreamText( @Nonnull String text );
+ @Nonnull
+ File dumpStreamException( @Nonnull Throwable t );
+
void logWarningAtEnd( @Nonnull String text );
@Nonnull
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire224WellFormedXmlFailuresIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire224WellFormedXmlFailuresIT.java
index b278c7a..1770c16 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire224WellFormedXmlFailuresIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire224WellFormedXmlFailuresIT.java
@@ -73,6 +73,6 @@ public class Surefire224WellFormedXmlFailuresIT
assertEquals( "Wrong error message", "<", testLower.getFailureMessage() );
assertEquals( "Wrong error message", ">", testGreater.getFailureMessage() );
// SUREFIRE-456 we have to doubly-escape non-visible control characters like \u0000
- assertEquals( "Wrong error message", "�", testU0000.getFailureMessage() );
+ assertEquals( "Wrong error message", "Hi � there!", testU0000.getFailureMessage() );
}
}
diff --git a/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java b/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java
index 7bb1afe..20f2736 100644
--- a/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java
+++ b/surefire-its/src/test/resources/surefire-224-wellFormedXmlFailures/src/test/java/wellFormedXmlFailures/TestSurefire3.java
@@ -56,7 +56,7 @@ public class TestSurefire3
public void testU0000()
{
- fail( "\u0000" );
+ fail( "Hi \u0000 there!" );
}
}