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/27 07:55:42 UTC
[maven-surefire] branch master updated: [SUREFIRE-1846] Remove
Base64 in the Encoder/Decoder and gain the performance for the
communication flow: Fork to Plugin
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/master by this push:
new c5319bf [SUREFIRE-1846] Remove Base64 in the Encoder/Decoder and gain the performance for the communication flow: Fork to Plugin
c5319bf is described below
commit c5319bf493c2929d13cd62d89c34704d5d5cb33a
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!" );
}
}