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 2022/03/04 09:48:08 UTC

[maven-surefire] branch SUREFIRE-2015 updated (7422201 -> 350954b)

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a change to branch SUREFIRE-2015
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.


    omit 7422201  [SUREFIRE-2014] Implement testRunId and RunMode in the EventEncoder and EventDecoder
     new 350954b  [SUREFIRE-2014] Implement testRunId and RunMode in the EventEncoder and EventDecoder

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (7422201)
            \
             N -- N -- N   refs/heads/SUREFIRE-2015 (350954b)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java  | 2 +-
 .../src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

[maven-surefire] 01/01: [SUREFIRE-2014] Implement testRunId and RunMode in the EventEncoder and EventDecoder

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch SUREFIRE-2015
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit 350954bd717617bbcb54aeef6fb94cd5d6af27b1
Author: tibordigana <ti...@apache.org>
AuthorDate: Fri Mar 4 03:50:35 2022 +0100

    [SUREFIRE-2014] Implement testRunId and RunMode in the EventEncoder and EventDecoder
---
 .../surefire/booterclient/output/ForkClient.java   |  16 +-
 .../output/ForkedProcessEventNotifier.java         |   3 +-
 .../output/ForkedProcessReportEventListener.java   |   3 +-
 .../maven/surefire/stream/CommandEncoder.java      |  27 ++-
 .../apache/maven/surefire/stream/EventDecoder.java | 123 +++++++------
 .../booterclient/ForkingRunListenerTest.java       |  20 ++-
 .../booterclient/TestSetMockReporterFactory.java   |   3 +-
 .../booterclient/output/ForkClientTest.java        |  56 ++++--
 .../output/ThreadedStreamConsumerTest.java         |   2 +-
 .../maven/plugin/surefire/extensions/E2ETest.java  |   4 +-
 .../extensions/EventConsumerThreadTest.java        |   1 +
 .../extensions/ForkedProcessEventNotifierTest.java |  18 +-
 .../surefire/extensions/StreamFeederTest.java      |   2 -
 .../maven/surefire/stream/EventDecoderTest.java    | 196 ++++++++++++---------
 .../api/booter/ForkedProcessEventType.java         |  34 ++--
 .../api/event/AbstractStandardStreamEvent.java     |  10 +-
 .../api/event/AbstractTestControlEvent.java        |  10 +-
 .../surefire/api/event/StandardStreamErrEvent.java |   4 +-
 .../event/StandardStreamErrWithNewLineEvent.java   |   4 +-
 .../surefire/api/event/StandardStreamOutEvent.java |   4 +-
 .../event/StandardStreamOutWithNewLineEvent.java   |   4 +-
 .../surefire/api/event/SystemPropertyEvent.java    |   9 +-
 .../api/event/TestAssumptionFailureEvent.java      |   5 +-
 .../maven/surefire/api/event/TestErrorEvent.java   |   5 +-
 .../maven/surefire/api/event/TestFailedEvent.java  |   5 +-
 .../maven/surefire/api/event/TestSkippedEvent.java |   5 +-
 .../surefire/api/event/TestStartingEvent.java      |   5 +-
 .../surefire/api/event/TestSucceededEvent.java     |   5 +-
 .../surefire/api/event/TestsetCompletedEvent.java  |   5 +-
 .../surefire/api/event/TestsetStartingEvent.java   |   5 +-
 .../surefire/api/stream/AbstractStreamDecoder.java |  45 +++--
 .../surefire/api/stream/AbstractStreamEncoder.java |  54 ++++--
 .../maven/surefire/api/stream/SegmentType.java     |   1 +
 .../api/stream/AbstractStreamDecoderTest.java      |   5 +-
 .../api/stream/AbstractStreamEncoderTest.java      | 114 ++++++------
 .../surefire/booter/spi/EventChannelEncoder.java   | 112 +++++-------
 .../surefire/booter/stream/CommandDecoder.java     |  20 +--
 .../maven/surefire/booter/CommandReaderTest.java   |   2 -
 .../booter/spi/CommandChannelDecoderTest.java      |   3 +-
 .../booter/spi/EventChannelEncoderTest.java        | 116 ++++++++++--
 .../resources/binary-commands/75171711-encoder.bin | Bin 851 -> 838 bytes
 .../junitplatform/JUnitPlatformProvider.java       |   2 +-
 .../maven/surefire/junit4/JUnit4Provider.java      |   2 +-
 43 files changed, 606 insertions(+), 463 deletions(-)

diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
index fc622ef..f89209b 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -125,7 +125,7 @@ public final class ForkClient
             implements ForkedProcessReportEventListener<TestSetReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, TestSetReportEntry reportEntry )
+        public void handle( TestSetReportEntry reportEntry )
         {
             getTestSetReporter().testSetStarting( reportEntry );
             setCurrentStartTime();
@@ -136,7 +136,7 @@ public final class ForkClient
             implements ForkedProcessReportEventListener<TestSetReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, TestSetReportEntry reportEntry )
+        public void handle( TestSetReportEntry reportEntry )
         {
             testsInProgress.clear();
             TestSetReportEntry entry = reportEntry( reportEntry.getRunMode(), reportEntry.getTestRunId(),
@@ -151,7 +151,7 @@ public final class ForkClient
     private final class TestStartingListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.offer( reportEntry.getSourceName() );
             getTestSetReporter().testStarting( reportEntry );
@@ -161,7 +161,7 @@ public final class ForkClient
     private final class TestSucceededListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.remove( reportEntry.getSourceName() );
             getTestSetReporter().testSucceeded( reportEntry );
@@ -171,7 +171,7 @@ public final class ForkClient
     private final class TestFailedListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.remove( reportEntry.getSourceName() );
             getTestSetReporter().testFailed( reportEntry );
@@ -181,7 +181,7 @@ public final class ForkClient
     private final class TestSkippedListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.remove( reportEntry.getSourceName() );
             getTestSetReporter().testSkipped( reportEntry );
@@ -191,7 +191,7 @@ public final class ForkClient
     private final class TestErrorListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.remove( reportEntry.getSourceName() );
             getTestSetReporter().testError( reportEntry );
@@ -201,7 +201,7 @@ public final class ForkClient
     private final class TestAssumptionFailureListener implements ForkedProcessReportEventListener<ReportEntry>
     {
         @Override
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             testsInProgress.remove( reportEntry.getSourceName() );
             getTestSetReporter().testAssumptionFailure( reportEntry );
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java
index 1c47afb..2e2a174 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java
@@ -225,11 +225,10 @@ public final class ForkedProcessEventNotifier
         {
             ForkedProcessReportEventListener listener = reportEventListeners.get( eventType );
             AbstractTestControlEvent testControlEvent = (AbstractTestControlEvent) event;
-            RunMode mode = testControlEvent.getRunMode();
             ReportEntry reportEntry = testControlEvent.getReportEntry();
             if ( listener != null )
             {
-                listener.handle( mode, reportEntry );
+                listener.handle( reportEntry );
             }
         }
         else if ( event.isJvmExitError() )
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
index 1eec0ba..10f393d 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessReportEventListener.java
@@ -20,7 +20,6 @@ package org.apache.maven.plugin.surefire.booterclient.output;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 /**
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
@@ -29,5 +28,5 @@ import org.apache.maven.surefire.api.report.RunMode;
  */
 public interface ForkedProcessReportEventListener<T extends ReportEntry>
 {
-    void handle( RunMode runMode, T reportEntry );
+    void handle( T reportEntry );
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/CommandEncoder.java b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/CommandEncoder.java
index 81f9d77..5da1151 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/CommandEncoder.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/CommandEncoder.java
@@ -38,7 +38,6 @@ import static org.apache.maven.surefire.api.booter.MasterProcessCommand.RUN_CLAS
 import static org.apache.maven.surefire.api.booter.MasterProcessCommand.SHUTDOWN;
 import static org.apache.maven.surefire.api.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
 import static org.apache.maven.surefire.api.booter.MasterProcessCommand.TEST_SET_FINISHED;
-import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
 
 /**
  *
@@ -56,52 +55,50 @@ public class CommandEncoder extends AbstractStreamEncoder<MasterProcessCommand>
     public void sendRunClass( String testClassName ) throws IOException
     {
         CharsetEncoder encoder = newCharsetEncoder();
-        int bufferMaxLength =
-            estimateBufferLength( RUN_CLASS.getOpcodeLength(), NORMAL_RUN, encoder, 0, testClassName );
+        int bufferMaxLength = estimateBufferLength( RUN_CLASS.getOpcodeLength(), null, encoder, 0, 0, testClassName );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encode( encoder, result, RUN_CLASS, NORMAL_RUN, testClassName );
+        encode( encoder, result, RUN_CLASS, testClassName );
         write( result, true );
     }
 
     public void sendTestSetFinished() throws IOException
     {
-        int bufferMaxLength = estimateBufferLength( TEST_SET_FINISHED.getOpcodeLength(), null, null, 0 );
+        int bufferMaxLength = estimateBufferLength( TEST_SET_FINISHED.getOpcodeLength(), null, null, 0, 0 );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, TEST_SET_FINISHED, null );
+        encodeHeader( result, TEST_SET_FINISHED );
         write( result, true );
     }
 
     public void sendSkipSinceNextTest() throws IOException
     {
-        int bufferMaxLength = estimateBufferLength( SKIP_SINCE_NEXT_TEST.getOpcodeLength(), null, null, 0 );
+        int bufferMaxLength = estimateBufferLength( SKIP_SINCE_NEXT_TEST.getOpcodeLength(), null, null, 0, 0 );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, SKIP_SINCE_NEXT_TEST, null );
+        encodeHeader( result, SKIP_SINCE_NEXT_TEST );
         write( result, true );
     }
 
     public void sendShutdown( String shutdownData ) throws IOException
     {
         CharsetEncoder encoder = newCharsetEncoder();
-        int bufferMaxLength =
-            estimateBufferLength( SHUTDOWN.getOpcodeLength(), null, encoder, 0, shutdownData );
+        int bufferMaxLength = estimateBufferLength( SHUTDOWN.getOpcodeLength(), null, encoder, 0, 0, shutdownData );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encode( encoder, result, SHUTDOWN, null, shutdownData );
+        encode( encoder, result, SHUTDOWN, shutdownData );
         write( result, true );
     }
 
     public void sendNoop() throws IOException
     {
-        int bufferMaxLength = estimateBufferLength( NOOP.getOpcodeLength(), null, null, 0 );
+        int bufferMaxLength = estimateBufferLength( NOOP.getOpcodeLength(), null, null, 0, 0 );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, NOOP, null );
+        encodeHeader( result, NOOP );
         write( result, true );
     }
 
     public void sendByeAck() throws IOException
     {
-        int bufferMaxLength = estimateBufferLength( BYE_ACK.getOpcodeLength(), null, null, 0 );
+        int bufferMaxLength = estimateBufferLength( BYE_ACK.getOpcodeLength(), null, null, 0, 0 );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, BYE_ACK, null );
+        encodeHeader( result, BYE_ACK );
         write( result, true );
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java
index aab8689..ea11889 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java
@@ -66,12 +66,12 @@ import java.util.concurrent.FutureTask;
 import static java.util.Collections.emptyMap;
 import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER_FOR_EVENTS_BYTES;
 import static org.apache.maven.surefire.api.report.CategorizedReportEntry.reportEntry;
-import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
 import static org.apache.maven.surefire.api.stream.SegmentType.DATA_INTEGER;
 import static org.apache.maven.surefire.api.stream.SegmentType.DATA_STRING;
 import static org.apache.maven.surefire.api.stream.SegmentType.END_OF_FRAME;
 import static org.apache.maven.surefire.api.stream.SegmentType.RUN_MODE;
 import static org.apache.maven.surefire.api.stream.SegmentType.STRING_ENCODING;
+import static org.apache.maven.surefire.api.stream.SegmentType.TEST_RUN_ID;
 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
 
 /**
@@ -102,15 +102,17 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
         END_OF_FRAME
     };
 
-    private static final SegmentType[] EVENT_WITH_RUNMODE_AND_ONE_STRING = new SegmentType[] {
+    private static final SegmentType[] EVENT_WITH_RUNMODE_TID_AND_ONE_STRING = new SegmentType[] {
         RUN_MODE,
+        TEST_RUN_ID,
         STRING_ENCODING,
         DATA_STRING,
         END_OF_FRAME
     };
 
-    private static final SegmentType[] EVENT_WITH_RUNMODE_AND_TWO_STRINGS = new SegmentType[] {
+    private static final SegmentType[] EVENT_WITH_RUNMODE_TID_AND_TWO_STRINGS = new SegmentType[] {
         RUN_MODE,
+        TEST_RUN_ID,
         STRING_ENCODING,
         DATA_STRING,
         DATA_STRING,
@@ -119,6 +121,7 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
 
     private static final SegmentType[] EVENT_TEST_CONTROL = new SegmentType[] {
         RUN_MODE,
+        TEST_RUN_ID,
         STRING_ENCODING,
         DATA_STRING,
         DATA_STRING,
@@ -155,13 +158,16 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
                 throw new MalformedFrameException( memento.getLine().getPositionByteBuffer(),
                     memento.getByteBuffer().position() );
             }
-            RunMode runMode = null;
+
             for ( SegmentType segmentType : nextSegmentType( eventType ) )
             {
                 switch ( segmentType )
                 {
                     case RUN_MODE:
-                        runMode = RUN_MODES.get( readSegment( memento ) );
+                        memento.getData().add( RUN_MODES.get( readSegment( memento ) ) );
+                        break;
+                    case TEST_RUN_ID:
+                        memento.getData().add( readLong( memento ) );
                         break;
                     case STRING_ENCODING:
                         memento.setCharset( readCharset( memento ) );
@@ -175,7 +181,7 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
                     case END_OF_FRAME:
                         memento.getLine().setPositionByteBuffer( memento.getByteBuffer().position() );
                         memento.getLine().clear();
-                        return toMessage( eventType, runMode, memento );
+                        return toMessage( eventType, memento );
                     default:
                         memento.getLine().setPositionByteBuffer( NO_POSITION );
                         getArguments()
@@ -244,9 +250,9 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
             case BOOTERCODE_STDOUT_NEW_LINE:
             case BOOTERCODE_STDERR:
             case BOOTERCODE_STDERR_NEW_LINE:
-                return EVENT_WITH_RUNMODE_AND_ONE_STRING;
+                return EVENT_WITH_RUNMODE_TID_AND_ONE_STRING;
             case BOOTERCODE_SYSPROPS:
-                return EVENT_WITH_RUNMODE_AND_TWO_STRINGS;
+                return EVENT_WITH_RUNMODE_TID_AND_TWO_STRINGS;
             case BOOTERCODE_TESTSET_STARTING:
             case BOOTERCODE_TESTSET_COMPLETED:
             case BOOTERCODE_TEST_STARTING:
@@ -263,9 +269,7 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
 
     @Override
     @Nonnull
-    protected final Event toMessage( @Nonnull ForkedProcessEventType eventType,
-                                     RunMode runMode,
-                                     @Nonnull Memento memento )
+    protected final Event toMessage( @Nonnull ForkedProcessEventType eventType, @Nonnull Memento memento )
         throws MalformedFrameException
     {
         switch ( eventType )
@@ -279,12 +283,12 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
             case BOOTERCODE_NEXT_TEST:
                 checkArguments( memento, 0 );
                 return new ControlNextTestEvent();
-            case BOOTERCODE_CONSOLE_ERROR:
-                checkArguments( memento, 3 );
-                return new ConsoleErrorEvent( toStackTraceWriter( memento.getData() ) );
             case BOOTERCODE_JVM_EXIT_ERROR:
                 checkArguments( memento, 3 );
                 return new JvmExitErrorEvent( toStackTraceWriter( memento.getData() ) );
+            case BOOTERCODE_CONSOLE_ERROR:
+                checkArguments( memento, 3 );
+                return new ConsoleErrorEvent( toStackTraceWriter( memento.getData() ) );
             case BOOTERCODE_CONSOLE_INFO:
                 checkArguments( memento, 1 );
                 return new ConsoleInfoEvent( (String) memento.getData().get( 0 ) );
@@ -295,46 +299,49 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
                 checkArguments( memento, 1 );
                 return new ConsoleWarningEvent( (String) memento.getData().get( 0 ) );
             case BOOTERCODE_STDOUT:
-                checkArguments( runMode, memento, 1 );
-                return new StandardStreamOutEvent( runMode, (String) memento.getData().get( 0 ) );
+                checkArguments( memento, 3 );
+                return new StandardStreamOutEvent( memento.ofDataAt( 0 ), memento.ofDataAt( 1 ),
+                    memento.ofDataAt( 2 ) );
             case BOOTERCODE_STDOUT_NEW_LINE:
-                checkArguments( runMode, memento, 1 );
-                return new StandardStreamOutWithNewLineEvent( runMode, (String) memento.getData().get( 0 ) );
+                checkArguments( memento, 3 );
+                return new StandardStreamOutWithNewLineEvent( memento.ofDataAt( 0 ), memento.ofDataAt( 1 ),
+                    memento.ofDataAt( 2 ) );
             case BOOTERCODE_STDERR:
-                checkArguments( runMode, memento, 1 );
-                return new StandardStreamErrEvent( runMode, (String) memento.getData().get( 0 ) );
+                checkArguments( memento, 3 );
+                return new StandardStreamErrEvent( memento.ofDataAt( 0 ), memento.ofDataAt( 1 ),
+                    memento.ofDataAt( 2 ) );
             case BOOTERCODE_STDERR_NEW_LINE:
-                checkArguments( runMode, memento, 1 );
-                return new StandardStreamErrWithNewLineEvent( runMode, (String) memento.getData().get( 0 ) );
+                checkArguments( memento, 3 );
+                return new StandardStreamErrWithNewLineEvent( memento.ofDataAt( 0 ), memento.ofDataAt( 1 ),
+                    memento.ofDataAt( 2 ) );
             case BOOTERCODE_SYSPROPS:
-                checkArguments( runMode, memento, 2 );
-                String key = (String) memento.getData().get( 0 );
-                String value = (String) memento.getData().get( 1 );
-                return new SystemPropertyEvent( runMode, key, value );
+                checkArguments( memento, 4 );
+                return new SystemPropertyEvent( memento.ofDataAt( 0 ), memento.ofDataAt( 1 ),
+                    memento.ofDataAt( 2 ), memento.ofDataAt( 3 ) );
             case BOOTERCODE_TESTSET_STARTING:
-                checkArguments( runMode, memento, 10 );
-                return new TestsetStartingEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestsetStartingEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TESTSET_COMPLETED:
-                checkArguments( runMode, memento, 10 );
-                return new TestsetCompletedEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestsetCompletedEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_STARTING:
-                checkArguments( runMode, memento, 10 );
-                return new TestStartingEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestStartingEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_SUCCEEDED:
-                checkArguments( runMode, memento, 10 );
-                return new TestSucceededEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestSucceededEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_FAILED:
-                checkArguments( runMode, memento, 10 );
-                return new TestFailedEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestFailedEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_SKIPPED:
-                checkArguments( runMode, memento, 10 );
-                return new TestSkippedEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestSkippedEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_ERROR:
-                checkArguments( runMode, memento, 10 );
-                return new TestErrorEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestErrorEvent( toReportEntry( memento.getData() ) );
             case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
-                checkArguments( runMode, memento, 10 );
-                return new TestAssumptionFailureEvent( runMode, toReportEntry( memento.getData() ) );
+                checkArguments( memento, 12 );
+                return new TestAssumptionFailureEvent( toReportEntry( memento.getData() ) );
             default:
                 throw new IllegalArgumentException( "Missing a branch for the event type " + eventType );
         }
@@ -343,19 +350,21 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
     @Nonnull
     private static TestSetReportEntry toReportEntry( List<Object> args )
     {
+        RunMode runMode = (RunMode) args.get( 0 );
+        long testRunId = (long) args.get( 1 );
         // 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 );
+        String source = (String) args.get( 2 );
+        String sourceText = (String) args.get( 3 );
+        String name = (String) args.get( 4 );
+        String nameText = (String) args.get( 5 );
+        String group = (String) args.get( 6 );
+        String message = (String) args.get( 7 );
+        Integer timeElapsed = (Integer) args.get( 8 );
         // 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,
+        String traceMessage = (String) args.get( 9 );
+        String smartTrimmedStackTrace = (String) args.get( 10 );
+        String stackTrace = (String) args.get( 11 );
+        return newReportEntry( runMode, testRunId, source, sourceText, name, nameText, group, message, timeElapsed,
             traceMessage, smartTrimmedStackTrace, stackTrace );
     }
 
@@ -374,8 +383,8 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
     }
 
     static TestSetReportEntry newReportEntry( // ReportEntry:
-                                              String source, String sourceText, String name,
-                                              String nameText, String group, String message,
+                                              RunMode runMode, long testRunId, String source, String sourceText,
+                                              String name, String nameText, String group, String message,
                                               Integer timeElapsed,
                                               // StackTraceWriter:
                                               String traceMessage,
@@ -383,8 +392,8 @@ public class EventDecoder extends AbstractStreamDecoder<Event, ForkedProcessEven
         throws NumberFormatException
     {
         StackTraceWriter stackTraceWriter = toTrace( traceMessage, smartTrimmedStackTrace, stackTrace );
-        return reportEntry( NORMAL_RUN /*todo*/, 0L /*todo*/, source, sourceText, name, nameText, group,
-            stackTraceWriter, timeElapsed, message, emptyMap() );
+        return reportEntry( runMode, testRunId, source, sourceText, name, nameText, group, stackTraceWriter,
+            timeElapsed, message, emptyMap() );
     }
 
     private static Map<Segment, ForkedProcessEventType> segmentsToEvents()
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 8eae70a..e595cba 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
@@ -185,7 +185,7 @@ public class ForkingRunListenerTest
     {
         final StandardTestRun standardTestRun = new StandardTestRun();
         TestOutputReceiver<TestOutputReportEntry> directConsoleReporter = standardTestRun.run();
-        directConsoleReporter.writeTestOutput( (TestOutputReportEntry) stdOut( "HeyYou" ) );
+        directConsoleReporter.writeTestOutput( new TestOutputReportEntry( stdOut( "HeyYou" ), NORMAL_RUN, 1L )  );
         standardTestRun.assertExpected( MockReporter.STDOUT, "HeyYou" );
     }
 
@@ -200,14 +200,18 @@ public class ForkingRunListenerTest
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
         ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), 1 );
 
-        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();
+        byte[] cmd = ( ":maven-surefire-event:\u0008:sys-prop:" + (char) 10 + ":normal-run:"
+            + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:"
+            + "\u0000\u0000\u0000\u0002:k1:\u0000\u0000\u0000\u0002:v1:" ).getBytes();
         for ( Event e : streamToEvent( cmd ) )
         {
             forkStreamClient.handleEvent( e );
         }
-        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();
+        cmd = ( "\n:maven-surefire-event:\u0008:sys-prop:" + (char) 10 + ":normal-run:"
+            + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:"
+            + "\u0000\u0000\u0000\u0002:k2:\u0000\u0000\u0000\u0002:v2:" ).getBytes();
         for ( Event e : streamToEvent( cmd ) )
         {
             forkStreamClient.handleEvent( e );
@@ -279,7 +283,7 @@ public class ForkingRunListenerTest
 
         MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
         assertThat( reporter.getFirstEvent() ).isEqualTo( MockReporter.TEST_STARTING );
-        //assertThat( reporter.getFirstData() ).isEqualTo( expected ); /*todo uncomment in SUREFIRE-2014*/
+        assertThat( reporter.getFirstData() ).isEqualTo( expected );
         assertThat( reporter.getEvents() ).hasSize( 1 );
 
         forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, 2 );
@@ -289,7 +293,7 @@ public class ForkingRunListenerTest
         }
         MockReporter reporter2 = (MockReporter) forkStreamClient.getReporter();
         assertThat( reporter2.getFirstEvent() ).isEqualTo( MockReporter.TEST_SKIPPED );
-        //assertThat( reporter2.getFirstData() ).isEqualTo( secondExpected ); /*todo uncomment in SUREFIRE-2014*/
+        assertThat( reporter2.getFirstData() ).isEqualTo( secondExpected );
         assertThat( reporter2.getEvents() ).hasSize( 1 );
     }
 
@@ -464,7 +468,7 @@ public class ForkingRunListenerTest
         {
             StackTraceWriter stackTraceWriter =
                 new LegacyPojoStackTraceWriter( "org.apache.tests.TestClass", "testMethod11", e );
-            return new CategorizedReportEntry( NORMAL_RUN, 0L,
+            return new CategorizedReportEntry( NORMAL_RUN, 1L,
                 "com.abc.TestClass", "testMethod", "aGroup", stackTraceWriter, 77 );
         }
     }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/TestSetMockReporterFactory.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/TestSetMockReporterFactory.java
index ff0bbb3..e46be43 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/TestSetMockReporterFactory.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/TestSetMockReporterFactory.java
@@ -25,6 +25,7 @@ import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
 import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
 import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
+import org.apache.maven.surefire.api.report.TestOutputReportEntry;
 import org.apache.maven.surefire.api.report.TestReportListener;
 
 import java.io.File;
@@ -43,7 +44,7 @@ public class TestSetMockReporterFactory
     }
 
     @Override
-    public TestReportListener createTestReportListener()
+    public TestReportListener<TestOutputReportEntry> createTestReportListener()
     {
         return new MockReporter();
     }
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 5d8251c..393d5c9 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
@@ -474,7 +474,7 @@ public class ForkClientTest
                 .thenReturn( receiver );
         NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new StandardStreamOutEvent( NORMAL_RUN, "msg" ) );
+        client.handleEvent( new StandardStreamOutEvent( NORMAL_RUN, 1L, "msg" ) );
         verifyZeroInteractions( notifiableTestStream );
         verify( factory, times( 1 ) )
                 .createTestReportListener();
@@ -516,7 +516,7 @@ public class ForkClientTest
                 .thenReturn( receiver );
         NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new StandardStreamOutWithNewLineEvent( NORMAL_RUN, "msg" ) );
+        client.handleEvent( new StandardStreamOutWithNewLineEvent( NORMAL_RUN, 1L, "msg" ) );
         verifyZeroInteractions( notifiableTestStream );
         verify( factory, times( 1 ) )
                 .createTestReportListener();
@@ -558,7 +558,7 @@ public class ForkClientTest
                 .thenReturn( receiver );
         NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new StandardStreamErrEvent( NORMAL_RUN, "msg" ) );
+        client.handleEvent( new StandardStreamErrEvent( NORMAL_RUN, 1L, "msg" ) );
         verifyZeroInteractions( notifiableTestStream );
         verify( factory, times( 1 ) )
                 .createTestReportListener();
@@ -600,7 +600,7 @@ public class ForkClientTest
                 .thenReturn( receiver );
         NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new StandardStreamErrWithNewLineEvent( NORMAL_RUN, "msg" ) );
+        client.handleEvent( new StandardStreamErrWithNewLineEvent( NORMAL_RUN, 1L, "msg" ) );
         verifyZeroInteractions( notifiableTestStream );
         verify( factory, times( 1 ) )
                 .createTestReportListener();
@@ -856,7 +856,7 @@ public class ForkClientTest
                 .thenReturn( receiver );
         NotifiableTestStream notifiableTestStream = mock( NotifiableTestStream.class );
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new SystemPropertyEvent( NORMAL_RUN, "k1", "v1" ) );
+        client.handleEvent( new SystemPropertyEvent( NORMAL_RUN, 1L, "k1", "v1" ) );
         verifyZeroInteractions( notifiableTestStream );
         verifyZeroInteractions( factory );
         assertThat( client.getReporter() )
@@ -909,6 +909,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -918,7 +920,7 @@ public class ForkClientTest
         when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
 
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new TestsetStartingEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestsetStartingEvent( reportEntry ) );
 
         client.tryToTimeout( System.currentTimeMillis() + 1000L, 1 );
 
@@ -1004,6 +1006,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1015,7 +1019,7 @@ public class ForkClientTest
         when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
 
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new TestsetStartingEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestsetStartingEvent( reportEntry ) );
         client.tryToTimeout( System.currentTimeMillis(), 1 );
 
         verifyZeroInteractions( notifiableTestStream );
@@ -1100,6 +1104,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1109,7 +1115,7 @@ public class ForkClientTest
         when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
 
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new TestsetCompletedEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestsetCompletedEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1193,6 +1199,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1202,7 +1210,7 @@ public class ForkClientTest
         when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
 
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestStartingEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1287,6 +1295,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1298,13 +1308,13 @@ public class ForkClientTest
         ForkClient client = new ForkClient( factory, notifiableTestStream,  0 );
         SimpleReportEntry testStarted =
             new SimpleReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(), null, null, null );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
+        client.handleEvent( new TestStartingEvent( testStarted ) );
 
         assertThat( client.testsInProgress() )
                 .hasSize( 1 )
                 .contains( "pkg.MyTest" );
 
-        client.handleEvent( new TestSucceededEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestSucceededEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1392,6 +1402,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1403,13 +1415,13 @@ public class ForkClientTest
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
         SimpleReportEntry testClass =
             new SimpleReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(), null, null, null );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, testClass ) );
+        client.handleEvent( new TestStartingEvent( testClass ) );
 
         assertThat( client.testsInProgress() )
                 .hasSize( 1 )
                 .contains( "pkg.MyTest" );
 
-        client.handleEvent( new TestFailedEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestFailedEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1503,6 +1515,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1514,13 +1528,13 @@ public class ForkClientTest
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
         SimpleReportEntry testStarted =
             new SimpleReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(), null, null, null );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
+        client.handleEvent( new TestStartingEvent( testStarted ) );
 
         assertThat( client.testsInProgress() )
                 .hasSize( 1 )
                 .contains( "pkg.MyTest" );
 
-        client.handleEvent( new TestSkippedEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestSkippedEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1612,6 +1626,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1624,13 +1640,13 @@ public class ForkClientTest
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
         SimpleReportEntry testStarted = new SimpleReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), null, null );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
+        client.handleEvent( new TestStartingEvent( testStarted ) );
 
         assertThat( client.testsInProgress() )
                 .hasSize( 1 )
                 .contains( "pkg.MyTest" );
 
-        client.handleEvent( new TestErrorEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestErrorEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
@@ -1718,6 +1734,8 @@ public class ForkClientTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "some test" );
@@ -1730,13 +1748,13 @@ public class ForkClientTest
         ForkClient client = new ForkClient( factory, notifiableTestStream, 0 );
         SimpleReportEntry testStarted =
             new SimpleReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(), null, null, null );
-        client.handleEvent( new TestStartingEvent( NORMAL_RUN, testStarted ) );
+        client.handleEvent( new TestStartingEvent( testStarted ) );
 
         assertThat( client.testsInProgress() )
                 .hasSize( 1 )
                 .contains( "pkg.MyTest" );
 
-        client.handleEvent( new TestAssumptionFailureEvent( NORMAL_RUN, reportEntry ) );
+        client.handleEvent( new TestAssumptionFailureEvent( reportEntry ) );
 
         verifyZeroInteractions( notifiableTestStream );
         verify( factory ).createTestReportListener();
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 5b5c3fa..804b76d 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
@@ -107,7 +107,7 @@ public class ThreadedStreamConsumerTest
 
         long t1 = System.currentTimeMillis();
 
-        Event event = new StandardStreamOutWithNewLineEvent( NORMAL_RUN, "" );
+        Event event = new StandardStreamOutWithNewLineEvent( NORMAL_RUN, 1L, "" );
         for ( int i = 0; i < 5_000_000; i++ )
         {
             streamConsumer.handleEvent( event );
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 304ed57..0904045 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
@@ -43,6 +43,7 @@ import org.apache.maven.surefire.api.event.Event;
 import org.apache.maven.surefire.api.fork.ForkNodeArguments;
 import org.apache.maven.surefire.api.report.OutputReportEntry;
 import org.apache.maven.surefire.api.report.TestOutputReceiver;
+import org.apache.maven.surefire.api.report.TestOutputReportEntry;
 import org.apache.maven.surefire.booter.spi.EventChannelEncoder;
 import org.apache.maven.surefire.booter.spi.SurefireMasterProcessChannelProcessorFactory;
 import org.apache.maven.surefire.extensions.CommandReader;
@@ -54,6 +55,7 @@ import org.junit.rules.ExpectedException;
 
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
 import static org.apache.maven.surefire.api.report.TestOutputReportEntry.stdOutln;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
@@ -156,7 +158,7 @@ public class E2ETest
                     for ( int i = 0; i < totalCalls; i++ )
                     {
                         //System.out.println( LONG_STRING );
-                        encoder.testOutput( stdOutln( LONG_STRING ) );
+                        encoder.testOutput( new TestOutputReportEntry( stdOutln( LONG_STRING ), NORMAL_RUN, 1L ) );
                     }
                     long t2 = System.currentTimeMillis();
                     long spent = t2 - t1;
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
index b22f0f8..3fac0e4 100644
--- 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
@@ -77,6 +77,7 @@ public class EventConsumerThreadTest
         event.put( ":std-out-stream:".getBytes( UTF_8 ) );
         event.put( (byte) 10 );
         event.put( ":normal-run:".getBytes( UTF_8 ) );
+        event.put( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:".getBytes( UTF_8 ) );
         event.put( (byte) 5 );
         event.put( ":UTF-8:".getBytes( UTF_8 ) );
         event.putInt( 100 );
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 a252077..f59c235 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
@@ -216,6 +216,8 @@ public class ForkedProcessEventNotifierTest
             when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
 
             ReportEntry reportEntry = mock( ReportEntry.class );
+            when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+            when( reportEntry.getTestRunId() ).thenReturn( 1L );
             when( reportEntry.getElapsed() ).thenReturn( 7 );
             when( reportEntry.getGroup() ).thenReturn( null );
             when( reportEntry.getMessage() ).thenReturn( null );
@@ -531,7 +533,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( (TestOutputReportEntry) stdOut( "msg" ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOut( "msg" ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -570,7 +572,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( (TestOutputReportEntry) stdOut( "" ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOut( "" ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -609,7 +611,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( (TestOutputReportEntry) stdOut( null ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOut( null ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -648,7 +650,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( stdOutln( "" ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOutln( "" ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -687,7 +689,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( stdOutln( null ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOutln( null ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -726,7 +728,7 @@ public class ForkedProcessEventNotifierTest
             final Stream out = Stream.newStream();
             WritableBufferedByteChannel wChannel = newBufferedChannel( out );
             EventChannelEncoder encoder = new EventChannelEncoder( wChannel );
-            encoder.testOutput( stdErr( "msg" ) );
+            encoder.testOutput( new TestOutputReportEntry( stdErr( "msg" ), NORMAL_RUN, 1L ) );
             wChannel.close();
 
             ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -922,6 +924,8 @@ public class ForkedProcessEventNotifierTest
             }
 
             TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+            when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+            when( reportEntry.getTestRunId() ).thenReturn( 1L );
             when( reportEntry.getElapsed() ).thenReturn( elapsed );
             when( reportEntry.getGroup() ).thenReturn( "this group" );
             when( reportEntry.getMessage() ).thenReturn( reportedMessage );
@@ -1100,7 +1104,7 @@ public class ForkedProcessEventNotifierTest
             this.hasStackTrace = hasStackTrace;
         }
 
-        public void handle( RunMode runMode, ReportEntry reportEntry )
+        public void handle( ReportEntry reportEntry )
         {
             called.set( true );
             assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
index 696286c..c7e3cd5 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
@@ -108,8 +108,6 @@ public class StreamFeederTest
             .append( ":maven-surefire-command:" )
             .append( (char) 13 )
             .append( ":run-testclass:" )
-            .append( (char) 10 )
-            .append( ":normal-run:" )
             .append( (char) 5 )
             .append( ":UTF-8:" )
             .append( (char) 0 )
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java
index 9f65264..efae6ee 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java
@@ -91,6 +91,8 @@ import static org.apache.maven.surefire.api.stream.SegmentType.DATA_STRING;
 import static org.apache.maven.surefire.api.stream.SegmentType.END_OF_FRAME;
 import static org.apache.maven.surefire.api.stream.SegmentType.RUN_MODE;
 import static org.apache.maven.surefire.api.stream.SegmentType.STRING_ENCODING;
+import static org.apache.maven.surefire.api.stream.SegmentType.TEST_RUN_ID;
+import static org.apache.maven.surefire.stream.EventDecoder.newReportEntry;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.powermock.api.mockito.PowerMockito.mock;
 import static org.powermock.api.mockito.PowerMockito.when;
@@ -177,83 +179,84 @@ public class EventDecoderTest
 
         segmentTypes = decoder.nextSegmentType( BOOTERCODE_STDOUT );
         assertThat( segmentTypes )
-            .hasSize( 4 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
+            .hasSize( 5 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE );
         assertThat( segmentTypes )
-            .hasSize( 4 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
+            .hasSize( 5 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDERR );
         assertThat( segmentTypes )
-            .hasSize( 4 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
+            .hasSize( 5 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE );
         assertThat( segmentTypes )
-            .hasSize( 4 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
+            .hasSize( 5 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( BOOTERCODE_SYSPROPS );
         assertThat( segmentTypes )
-            .hasSize( 5 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME } );
+            .hasSize( 6 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( BOOTERCODE_TESTSET_STARTING );
         assertThat( segmentTypes )
-            .hasSize( 13 )
+            .hasSize( 14 )
             .isEqualTo( new SegmentType[] {
-                RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
+                RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING,
                 DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING, END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_STARTING );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( BOOTERCODE_TEST_SUCCEEDED );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( BOOTERCODE_TEST_FAILED );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_ERROR );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
 
         segmentTypes = decoder.nextSegmentType( ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE );
         assertThat( segmentTypes )
-            .hasSize( 13 )
-            .isEqualTo( new SegmentType[] { RUN_MODE, STRING_ENCODING, DATA_STRING, DATA_STRING, DATA_STRING,
-                DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
+            .hasSize( 14 )
+            .isEqualTo( new SegmentType[] { RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING,
+                DATA_STRING, DATA_STRING, DATA_STRING, DATA_STRING, DATA_INTEGER, DATA_STRING, DATA_STRING, DATA_STRING,
                 END_OF_FRAME } );
     }
 
@@ -264,21 +267,21 @@ public class EventDecoderTest
         Channel channel = new Channel( stream, 1 );
         EventDecoder decoder = new EventDecoder( channel, new MockForkNodeArguments() );
 
-        Event event = decoder.toMessage( BOOTERCODE_BYE, NORMAL_RUN, decoder.new Memento() );
+        Event event = decoder.toMessage( BOOTERCODE_BYE, decoder.new Memento() );
         assertThat( event )
             .isInstanceOf( ControlByeEvent.class );
 
-        event = decoder.toMessage( BOOTERCODE_STOP_ON_NEXT_TEST, NORMAL_RUN, decoder.new Memento() );
+        event = decoder.toMessage( BOOTERCODE_STOP_ON_NEXT_TEST, decoder.new Memento() );
         assertThat( event )
             .isInstanceOf( ControlStopOnNextTestEvent.class );
 
-        event = decoder.toMessage( BOOTERCODE_NEXT_TEST, NORMAL_RUN, decoder.new Memento() );
+        event = decoder.toMessage( BOOTERCODE_NEXT_TEST, decoder.new Memento() );
         assertThat( event )
             .isInstanceOf( ControlNextTestEvent.class );
 
         Memento memento = decoder.new Memento();
         memento.getData().addAll( asList( "1", "2", "3" ) );
-        event = decoder.toMessage( BOOTERCODE_CONSOLE_ERROR, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_CONSOLE_ERROR, memento );
         assertThat( event )
             .isInstanceOf( ConsoleErrorEvent.class );
         ConsoleErrorEvent consoleErrorEvent = (ConsoleErrorEvent) event;
@@ -291,7 +294,7 @@ public class EventDecoderTest
 
         memento = decoder.new Memento();
         memento.getData().addAll( asList( null, null, null ) );
-        event = decoder.toMessage( BOOTERCODE_CONSOLE_ERROR, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_CONSOLE_ERROR, memento );
         assertThat( event )
             .isInstanceOf( ConsoleErrorEvent.class );
         consoleErrorEvent = (ConsoleErrorEvent) event;
@@ -300,7 +303,7 @@ public class EventDecoderTest
 
         memento = decoder.new Memento();
         memento.getData().addAll( asList( "1", "2", "3" ) );
-        event = decoder.toMessage( BOOTERCODE_JVM_EXIT_ERROR, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_JVM_EXIT_ERROR, memento );
         assertThat( event )
             .isInstanceOf( JvmExitErrorEvent.class );
         JvmExitErrorEvent jvmExitErrorEvent = (JvmExitErrorEvent) event;
@@ -313,7 +316,7 @@ public class EventDecoderTest
 
         memento = decoder.new Memento();
         memento.getData().addAll( asList( null, null, null ) );
-        event = decoder.toMessage( BOOTERCODE_JVM_EXIT_ERROR, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_JVM_EXIT_ERROR, memento );
         assertThat( event )
             .isInstanceOf( JvmExitErrorEvent.class );
         jvmExitErrorEvent = (JvmExitErrorEvent) event;
@@ -322,64 +325,70 @@ public class EventDecoderTest
 
         memento = decoder.new Memento();
         memento.getData().addAll( singletonList( "m" ) );
-        event = decoder.toMessage( BOOTERCODE_CONSOLE_INFO, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_CONSOLE_INFO, memento );
         assertThat( event ).isInstanceOf( ConsoleInfoEvent.class );
         assertThat( ( (ConsoleInfoEvent) event ).getMessage() ).isEqualTo( "m" );
 
         memento = decoder.new Memento();
         memento.getData().addAll( singletonList( "" ) );
-        event = decoder.toMessage( BOOTERCODE_CONSOLE_WARNING, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_CONSOLE_WARNING, memento );
         assertThat( event ).isInstanceOf( ConsoleWarningEvent.class );
         assertThat( ( (ConsoleWarningEvent) event ).getMessage() ).isEmpty();
 
         memento = decoder.new Memento();
         memento.getData().addAll( singletonList( null ) );
-        event = decoder.toMessage( BOOTERCODE_CONSOLE_DEBUG, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_CONSOLE_DEBUG, memento );
         assertThat( event ).isInstanceOf( ConsoleDebugEvent.class );
         assertThat( ( (ConsoleDebugEvent) event ).getMessage() ).isNull();
 
         memento = decoder.new Memento();
-        memento.getData().addAll( singletonList( "m" ) );
-        event = decoder.toMessage( BOOTERCODE_STDOUT, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "m" ) );
+        event = decoder.toMessage( BOOTERCODE_STDOUT, memento );
         assertThat( event ).isInstanceOf( StandardStreamOutEvent.class );
         assertThat( ( (StandardStreamOutEvent) event ).getMessage() ).isEqualTo( "m" );
         assertThat( ( (StandardStreamOutEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (StandardStreamOutEvent) event ).getTestRunId() ).isEqualTo( 1L );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( singletonList( null ) );
-        event = decoder.toMessage( BOOTERCODE_STDOUT_NEW_LINE, RERUN_TEST_AFTER_FAILURE, memento );
+        memento.getData().addAll( asList( RERUN_TEST_AFTER_FAILURE, 1L, null ) );
+        event = decoder.toMessage( BOOTERCODE_STDOUT_NEW_LINE, memento );
         assertThat( event ).isInstanceOf( StandardStreamOutWithNewLineEvent.class );
         assertThat( ( (StandardStreamOutWithNewLineEvent) event ).getMessage() ).isNull();
         assertThat( ( (StandardStreamOutWithNewLineEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+        assertThat( ( (StandardStreamOutWithNewLineEvent) event ).getTestRunId() ).isEqualTo( 1L );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( singletonList( null ) );
-        event = decoder.toMessage( BOOTERCODE_STDERR, RERUN_TEST_AFTER_FAILURE, memento );
+        memento.getData().addAll( asList( RERUN_TEST_AFTER_FAILURE, 1L, null ) );
+        event = decoder.toMessage( BOOTERCODE_STDERR, memento );
         assertThat( event ).isInstanceOf( StandardStreamErrEvent.class );
         assertThat( ( (StandardStreamErrEvent) event ).getMessage() ).isNull();
         assertThat( ( (StandardStreamErrEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+        assertThat( ( (StandardStreamErrEvent) event ).getTestRunId() ).isEqualTo( 1L );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( singletonList( "abc" ) );
-        event = decoder.toMessage( BOOTERCODE_STDERR_NEW_LINE, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "abc" ) );
+        event = decoder.toMessage( BOOTERCODE_STDERR_NEW_LINE, memento );
         assertThat( event ).isInstanceOf( StandardStreamErrWithNewLineEvent.class );
         assertThat( ( (StandardStreamErrWithNewLineEvent) event ).getMessage() ).isEqualTo( "abc" );
         assertThat( ( (StandardStreamErrWithNewLineEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (StandardStreamErrWithNewLineEvent) event ).getTestRunId() ).isEqualTo( 1L );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "key", "value" ) );
-        event = decoder.toMessage( BOOTERCODE_SYSPROPS, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "key", "value" ) );
+        event = decoder.toMessage( BOOTERCODE_SYSPROPS, memento );
         assertThat( event ).isInstanceOf( SystemPropertyEvent.class );
+        assertThat( ( (SystemPropertyEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (SystemPropertyEvent) event ).getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (SystemPropertyEvent) event ).getKey() ).isEqualTo( "key" );
         assertThat( ( (SystemPropertyEvent) event ).getValue() ).isEqualTo( "value" );
-        assertThat( ( (SystemPropertyEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", "sourceText", "name", "nameText", "group", "message", 5,
-            "traceMessage", "smartTrimmedStackTrace", "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TESTSET_STARTING, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN , 1L, "source", "sourceText", "name", "nameText", "group",
+            "message", 5, "traceMessage", "smartTrimmedStackTrace", "stackTrace" ) );
+        event = decoder.toMessage( BOOTERCODE_TESTSET_STARTING, memento );
         assertThat( event ).isInstanceOf( TestsetStartingEvent.class );
-        assertThat( ( (TestsetStartingEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
         assertThat( ( (TestsetStartingEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -396,11 +405,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", "sourceText", "name", "nameText", "group", null, 5,
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", "sourceText", "name", "nameText", "group", null, 5,
             "traceMessage", "smartTrimmedStackTrace", "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TESTSET_COMPLETED, NORMAL_RUN, memento );
+        event = decoder.toMessage( BOOTERCODE_TESTSET_COMPLETED, memento );
         assertThat( event ).isInstanceOf( TestsetCompletedEvent.class );
-        assertThat( ( (TestsetCompletedEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
         assertThat( ( (TestsetCompletedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -417,11 +427,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", "sourceText", "name", "nameText", "group", "message", 5,
-            null, "smartTrimmedStackTrace", "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_STARTING, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", "sourceText", "name", "nameText", "group",
+            "message", 5, null, "smartTrimmedStackTrace", "stackTrace" ) );
+        event = decoder.toMessage( BOOTERCODE_TEST_STARTING, memento );
         assertThat( event ).isInstanceOf( TestStartingEvent.class );
-        assertThat( ( (TestStartingEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestStartingEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestStartingEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestStartingEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestStartingEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
         assertThat( ( (TestStartingEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -438,11 +449,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData()
-            .addAll( asList( "source", "sourceText", "name", "nameText", "group", "message", 5, null, null, null ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_SUCCEEDED, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", "sourceText", "name", "nameText", "group",
+            "message", 5, null, null, null ) );
+        event = decoder.toMessage( BOOTERCODE_TEST_SUCCEEDED, memento );
         assertThat( event ).isInstanceOf( TestSucceededEvent.class );
-        assertThat( ( (TestSucceededEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestSucceededEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestSucceededEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestSucceededEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestSucceededEvent) event ).getReportEntry().getSourceText() ).isEqualTo( "sourceText" );
         assertThat( ( (TestSucceededEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -453,11 +465,12 @@ public class EventDecoderTest
         assertThat( ( (TestSucceededEvent) event ).getReportEntry().getStackTraceWriter() ).isNull();
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", null, "name", null, "group", null, 5,
+        memento.getData().addAll( asList( RERUN_TEST_AFTER_FAILURE, 1L, "source", null, "name", null, "group", null, 5,
             "traceMessage", "smartTrimmedStackTrace", "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_FAILED, RERUN_TEST_AFTER_FAILURE, memento );
+        event = decoder.toMessage( BOOTERCODE_TEST_FAILED, memento );
         assertThat( event ).isInstanceOf( TestFailedEvent.class );
-        assertThat( ( (TestFailedEvent) event ).getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+        assertThat( ( (TestFailedEvent) event ).getReportEntry().getRunMode() ).isEqualTo( RERUN_TEST_AFTER_FAILURE );
+        assertThat( ( (TestFailedEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestFailedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestFailedEvent) event ).getReportEntry().getSourceText() ).isNull();
         assertThat( ( (TestFailedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -474,10 +487,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", null, "name", null, null, null, 5, null, null, "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_SKIPPED, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", null, "name", null, null, null, 5, null, null,
+            "stackTrace" ) );
+        event = decoder.toMessage( BOOTERCODE_TEST_SKIPPED, memento );
         assertThat( event ).isInstanceOf( TestSkippedEvent.class );
-        assertThat( ( (TestSkippedEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestSkippedEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestSkippedEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestSkippedEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestSkippedEvent) event ).getReportEntry().getSourceText() ).isNull();
         assertThat( ( (TestSkippedEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -496,11 +511,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData()
-            .addAll( asList( "source", null, "name", "nameText", null, null, 0, null, null, "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_ERROR, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", null, "name", "nameText", null, null, 0, null, null,
+            "stackTrace" ) );
+        event = decoder.toMessage( BOOTERCODE_TEST_ERROR, memento );
         assertThat( event ).isInstanceOf( TestErrorEvent.class );
-        assertThat( ( (TestErrorEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestErrorEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestErrorEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestErrorEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestErrorEvent) event ).getReportEntry().getSourceText() ).isNull();
         assertThat( ( (TestErrorEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -519,10 +535,12 @@ public class EventDecoderTest
             .isEqualTo( "stackTrace" );
 
         memento = decoder.new Memento();
-        memento.getData().addAll( asList( "source", null, "name", null, "group", null, 5, null, null, "stackTrace" ) );
-        event = decoder.toMessage( BOOTERCODE_TEST_ASSUMPTIONFAILURE, NORMAL_RUN, memento );
+        memento.getData().addAll( asList( NORMAL_RUN, 1L, "source", null, "name", null, "group", null, 5, null, null,
+            "stackTrace" ) );
+        event = decoder.toMessage( BOOTERCODE_TEST_ASSUMPTIONFAILURE, memento );
         assertThat( event ).isInstanceOf( TestAssumptionFailureEvent.class );
-        assertThat( ( (TestAssumptionFailureEvent) event ).getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getTestRunId() ).isEqualTo( 1L );
         assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getSourceName() ).isEqualTo( "source" );
         assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getSourceText() ).isNull();
         assertThat( ( (TestAssumptionFailureEvent) event ).getReportEntry().getName() ).isEqualTo( "name" );
@@ -544,8 +562,10 @@ public class EventDecoderTest
     @Test
     public void shouldRecognizeEmptyStream4ReportEntry()
     {
-        ReportEntry reportEntry = EventDecoder.newReportEntry( "", "", "", "", "", "", null, "", "", "" );
+        ReportEntry reportEntry = newReportEntry( NORMAL_RUN, 1L, "", "", "", "", "", "", null, "", "", "" );
         assertThat( reportEntry ).isNotNull();
+        assertThat( reportEntry.getRunMode() ).isEqualTo( NORMAL_RUN );
+        assertThat( reportEntry.getTestRunId() ).isEqualTo( 1L );
         assertThat( reportEntry.getStackTraceWriter() ).isNotNull();
         assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() ).isEmpty();
         assertThat( reportEntry.getStackTraceWriter().writeTraceToString() ).isEmpty();
@@ -587,7 +607,7 @@ public class EventDecoderTest
         when( reportEntry.getSourceText() ).thenReturn( "test class display name" );
         when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
 
-        ReportEntry decodedReportEntry = EventDecoder.newReportEntry( reportEntry.getSourceName(),
+        ReportEntry decodedReportEntry = newReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
             reportEntry.getMessage(), null, null, null, null );
 
@@ -600,7 +620,7 @@ public class EventDecoderTest
         assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
         assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
 
-        decodedReportEntry = EventDecoder.newReportEntry( reportEntry.getSourceName(),
+        decodedReportEntry = newReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
             reportEntry.getMessage(), null, exceptionMessage, smartStackTrace, null );
 
@@ -620,7 +640,7 @@ public class EventDecoderTest
         assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
             .isNull();
 
-        decodedReportEntry = EventDecoder.newReportEntry( reportEntry.getSourceName(),
+        decodedReportEntry = newReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
             reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, null );
 
@@ -640,7 +660,7 @@ public class EventDecoderTest
         assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() )
             .isNull();
 
-        decodedReportEntry = EventDecoder.newReportEntry( reportEntry.getSourceName(),
+        decodedReportEntry = newReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
             reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, stackTrace );
 
@@ -661,7 +681,7 @@ public class EventDecoderTest
         assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
         assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
 
-        decodedReportEntry = EventDecoder.newReportEntry( reportEntry.getSourceName(),
+        decodedReportEntry = newReportEntry( NORMAL_RUN, 1L, reportEntry.getSourceName(),
             reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(), reportEntry.getGroup(),
             reportEntry.getMessage(), 1003, exceptionMessage, smartStackTrace, trimmedStackTrace );
 
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 94da335..f82bb51 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
@@ -33,7 +33,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:sys-prop:RunMode:0x0000000100000000:5:UTF-8:0xFFFFFFFF:key:0xFFFFFFFF:value:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -45,7 +45,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:testset-starting:RunMode:0x0000000100000000:5: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>
@@ -57,7 +57,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:testset-completed:RunMode:0x0000000100000000:5: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>
@@ -69,7 +69,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-starting:RunMode:0x0000000100000001:5: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>
@@ -81,7 +81,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-succeeded:RunMode:0x0000000100000001:5: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>
@@ -93,7 +93,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-failed:RunMode:0x0000000100000001:5: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>
@@ -105,7 +105,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-skipped:RunMode:0x0000000100000001:5: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>
@@ -117,7 +117,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-error:RunMode:0x0000000100000001:5: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>
@@ -129,7 +129,7 @@ public enum ForkedProcessEventType
     /**
      * 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 ):
+     * :maven-surefire-event:test-assumption-failure:RunMode:0x0000000100000001:5: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>
@@ -141,7 +141,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:std-out-stream:RunMode:0x0000000100000001:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -153,7 +153,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:std-out-stream-new-line:RunMode:0x0000000100000001:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -165,7 +165,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:std-err-stream:RunMode:0x0000000100000001:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -177,7 +177,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:std-err-stream-new-line:RunMode:0x0000000100000001:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -189,7 +189,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:console-info-log:RunMode:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -201,7 +201,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:console-debug-log:RunMode:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -213,7 +213,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:console-warning-log:RunMode:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
@@ -225,7 +225,7 @@ public enum ForkedProcessEventType
     /**
      * 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:
+     * :maven-surefire-event:console-error-log:RunMode:5:UTF-8:0xFFFFFFFF:line:
      * </pre>
      * The constructor with one argument:
      * <ul>
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java
index bebb35e..4393ee3 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java
@@ -30,12 +30,15 @@ import org.apache.maven.surefire.api.report.RunMode;
 public abstract class AbstractStandardStreamEvent extends Event
 {
     private final RunMode runMode;
+    private final Long testRunId;
     private final String message;
 
-    protected AbstractStandardStreamEvent( ForkedProcessEventType eventType, RunMode runMode, String message )
+    protected AbstractStandardStreamEvent( ForkedProcessEventType eventType, RunMode runMode, Long testRunId,
+                                           String message )
     {
         super( eventType );
         this.runMode = runMode;
+        this.testRunId = testRunId;
         this.message = message;
     }
 
@@ -44,6 +47,11 @@ public abstract class AbstractStandardStreamEvent extends Event
         return runMode;
     }
 
+    public Long getTestRunId()
+    {
+        return testRunId;
+    }
+
     public String getMessage()
     {
         return message;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractTestControlEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractTestControlEvent.java
index 747f65c..a43ed33 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractTestControlEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractTestControlEvent.java
@@ -21,7 +21,6 @@ package org.apache.maven.surefire.api.event;
 
 import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 /**
  * The base class of an event of test control.
@@ -31,21 +30,14 @@ import org.apache.maven.surefire.api.report.RunMode;
  */
 public abstract class AbstractTestControlEvent<T extends ReportEntry> extends Event
 {
-    private final RunMode runMode;
     private final T reportEntry;
 
-    public AbstractTestControlEvent( ForkedProcessEventType eventType, RunMode runMode, T reportEntry )
+    public AbstractTestControlEvent( ForkedProcessEventType eventType, T reportEntry )
     {
         super( eventType );
-        this.runMode = runMode;
         this.reportEntry = reportEntry;
     }
 
-    public RunMode getRunMode()
-    {
-        return runMode;
-    }
-
     public T getReportEntry()
     {
         return reportEntry;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java
index 3367edf..7188b8b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java
@@ -30,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class StandardStreamErrEvent extends AbstractStandardStreamEvent
 {
-    public StandardStreamErrEvent( RunMode runMode, String message )
+    public StandardStreamErrEvent( RunMode runMode, Long testRunId, String message )
     {
-        super( BOOTERCODE_STDERR, runMode, message );
+        super( BOOTERCODE_STDERR, runMode, testRunId, message );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java
index 2974e5a..968dcb3 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java
@@ -30,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class StandardStreamErrWithNewLineEvent extends AbstractStandardStreamEvent
 {
-    public StandardStreamErrWithNewLineEvent( RunMode runMode, String message )
+    public StandardStreamErrWithNewLineEvent( RunMode runMode, Long testRunId, String message )
     {
-        super( BOOTERCODE_STDERR_NEW_LINE, runMode, message );
+        super( BOOTERCODE_STDERR_NEW_LINE, runMode, testRunId, message );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java
index 9c77edd..1525de7 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java
@@ -30,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class StandardStreamOutEvent extends AbstractStandardStreamEvent
 {
-    public StandardStreamOutEvent( RunMode runMode, String message )
+    public StandardStreamOutEvent( RunMode runMode, Long testRunId, String message )
     {
-        super( BOOTERCODE_STDOUT, runMode, message );
+        super( BOOTERCODE_STDOUT, runMode, testRunId, message );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java
index 34d9f8d..b566bf9 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java
@@ -30,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class StandardStreamOutWithNewLineEvent extends AbstractStandardStreamEvent
 {
-    public StandardStreamOutWithNewLineEvent( RunMode runMode, String message )
+    public StandardStreamOutWithNewLineEvent( RunMode runMode, Long testRunId, String message )
     {
-        super( BOOTERCODE_STDOUT_NEW_LINE, runMode, message );
+        super( BOOTERCODE_STDOUT_NEW_LINE, runMode, testRunId, message );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/SystemPropertyEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/SystemPropertyEvent.java
index a0ae1e4..0b293b5 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/SystemPropertyEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/SystemPropertyEvent.java
@@ -31,13 +31,15 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
 public final class SystemPropertyEvent extends Event
 {
     private final RunMode runMode;
+    private final Long testRunId;
     private final String key;
     private final String value;
 
-    public SystemPropertyEvent( RunMode runMode, String key, String value )
+    public SystemPropertyEvent( RunMode runMode, Long testRunId, String key, String value )
     {
         super( BOOTERCODE_SYSPROPS );
         this.runMode = runMode;
+        this.testRunId = testRunId;
         this.key = key;
         this.value = value;
     }
@@ -47,6 +49,11 @@ public final class SystemPropertyEvent extends Event
         return runMode;
     }
 
+    public Long getTestRunId()
+    {
+        return testRunId;
+    }
+
     public String getKey()
     {
         return key;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestAssumptionFailureEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestAssumptionFailureEvent.java
index ee1b466..c702dc8 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestAssumptionFailureEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestAssumptionFailureEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestAssumptionFailureEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestAssumptionFailureEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestAssumptionFailureEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry );
+        super( BOOTERCODE_TEST_ASSUMPTIONFAILURE, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestErrorEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestErrorEvent.java
index f85fc5d..a66f63c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestErrorEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestErrorEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestErrorEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestErrorEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestErrorEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_ERROR, runMode, reportEntry );
+        super( BOOTERCODE_TEST_ERROR, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestFailedEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestFailedEvent.java
index 30c8994..1905e07 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestFailedEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestFailedEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestFailedEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestFailedEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestFailedEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_FAILED, runMode, reportEntry );
+        super( BOOTERCODE_TEST_FAILED, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSkippedEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSkippedEvent.java
index 3ec406d..f33b528 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSkippedEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSkippedEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestSkippedEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestSkippedEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestSkippedEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry );
+        super( BOOTERCODE_TEST_SKIPPED, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestStartingEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestStartingEvent.java
index 94818d0..9ef3e71 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestStartingEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestStartingEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestStartingEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestStartingEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestStartingEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_STARTING, runMode, reportEntry );
+        super( BOOTERCODE_TEST_STARTING, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSucceededEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSucceededEvent.java
index dd4005b..fad36eb 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSucceededEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestSucceededEvent.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.api.event;
  */
 
 import org.apache.maven.surefire.api.report.ReportEntry;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
 
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestSucceededEvent extends AbstractTestControlEvent<ReportEntry>
 {
-    public TestSucceededEvent( RunMode runMode, ReportEntry reportEntry )
+    public TestSucceededEvent( ReportEntry reportEntry )
     {
-        super( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry );
+        super( BOOTERCODE_TEST_SUCCEEDED, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetCompletedEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetCompletedEvent.java
index e20c44c..2d82a39 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetCompletedEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetCompletedEvent.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.api.event;
  * under the License.
  */
 
-import org.apache.maven.surefire.api.report.RunMode;
 import org.apache.maven.surefire.api.report.TestSetReportEntry;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestsetCompletedEvent extends AbstractTestControlEvent<TestSetReportEntry>
 {
-    public TestsetCompletedEvent( RunMode runMode, TestSetReportEntry reportEntry )
+    public TestsetCompletedEvent( TestSetReportEntry reportEntry )
     {
-        super( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry );
+        super( BOOTERCODE_TESTSET_COMPLETED, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetStartingEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetStartingEvent.java
index 4faf3ac..5518f0d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetStartingEvent.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/TestsetStartingEvent.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.api.event;
  * under the License.
  */
 
-import org.apache.maven.surefire.api.report.RunMode;
 import org.apache.maven.surefire.api.report.TestSetReportEntry;
 
 import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
@@ -31,8 +30,8 @@ import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTER
  */
 public final class TestsetStartingEvent extends AbstractTestControlEvent<TestSetReportEntry>
 {
-    public TestsetStartingEvent( RunMode runMode, TestSetReportEntry reportEntry )
+    public TestsetStartingEvent( TestSetReportEntry reportEntry )
     {
-        super( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry );
+        super( BOOTERCODE_TESTSET_STARTING, reportEntry );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java
index de197d5..facf30b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java
@@ -21,7 +21,6 @@ package org.apache.maven.surefire.api.stream;
 
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.api.fork.ForkNodeArguments;
-import org.apache.maven.surefire.api.report.RunMode;
 
 import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
@@ -73,6 +72,7 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
     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 LONG_LENGTH = 8;
 
     private final ReadableByteChannel channel;
     private final ForkNodeArguments arguments;
@@ -98,7 +98,7 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
     protected abstract ST[] nextSegmentType( @Nonnull MT messageType );
 
     @Nonnull
-    protected abstract M toMessage( @Nonnull MT messageType, RunMode runMode, @Nonnull Memento memento )
+    protected abstract M toMessage( @Nonnull MT messageType, @Nonnull Memento memento )
         throws MalformedFrameException;
 
     @Nonnull
@@ -229,6 +229,27 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
         return i;
     }
 
+    protected Long readLong( @Nonnull Memento memento ) throws IOException, MalformedFrameException
+    {
+        read( memento, BYTE_LENGTH );
+        boolean isNullObject = memento.getByteBuffer().get() == 0;
+        if ( isNullObject )
+        {
+            read( memento, DELIMITER_LENGTH );
+            checkDelimiter( memento );
+            return null;
+        }
+        return readLongPrivate( memento );
+    }
+
+    protected long readLongPrivate( @Nonnull Memento memento ) throws IOException, MalformedFrameException
+    {
+        read( memento, LONG_LENGTH + DELIMITER_LENGTH );
+        long num = memento.getByteBuffer().getLong();
+        checkDelimiter( memento );
+        return num;
+    }
+
     @SuppressWarnings( "checkstyle:magicnumber" )
     protected final void checkDelimiter( Memento memento ) throws MalformedFrameException
     {
@@ -249,10 +270,11 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
         try
         {
             byte[] header = getEncodedMagicNumber();
+            byte[] bbArray = bb.array();
             for ( int start = bb.arrayOffset() + ( (Buffer) bb ).position(), length = header.length;
                   shift < length; shift++ )
             {
-                if ( bb.array()[shift + start] != header[shift] )
+                if ( bbArray[shift + start] != header[shift] )
                 {
                     throw new MalformedFrameException( memento.getLine().getPositionByteBuffer(),
                         ( (Buffer) bb ).position() + shift );
@@ -267,17 +289,6 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
         checkDelimiter( memento );
     }
 
-    protected void checkArguments( RunMode runMode, Memento memento, int expectedDataElements )
-        throws MalformedFrameException
-    {
-        if ( runMode == null )
-        {
-            throw new MalformedFrameException( memento.getLine().getPositionByteBuffer(),
-                ( (Buffer) memento.getByteBuffer() ).position() );
-        }
-        checkArguments( memento, expectedDataElements );
-    }
-
     protected void checkArguments( Memento memento, int expectedDataElements )
         throws MalformedFrameException
     {
@@ -555,6 +566,12 @@ public abstract class AbstractStreamDecoder<M, MT extends Enum<MT>, ST extends E
             return data;
         }
 
+        public <T> T ofDataAt( int indexOfData )
+        {
+            //noinspection unchecked
+            return (T) data.get( indexOfData );
+        }
+
         public CharBuffer getCharBuffer()
         {
             return cb;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoder.java
index 758c1f9..9d3b765 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoder.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoder.java
@@ -79,7 +79,25 @@ public abstract class AbstractStreamEncoder<E extends Enum<E>>
         }
     }
 
-    public void encodeHeader( ByteBuffer result, E operation, RunMode runMode )
+    public void encodeHeader( ByteBuffer result, E operation, RunMode runMode, Long testRunId )
+    {
+        encodeHeader( result, operation );
+
+        byte[] runmode = runMode == null ? new byte[0] : runMode.getRunmodeBinary();
+        result.put( (byte) runmode.length );
+        result.put( (byte) ':' );
+        result.put( runmode );
+        result.put( (byte) ':' );
+
+        result.put( (byte) ( testRunId == null ? 0 : 1 ) );
+        if ( testRunId != null )
+        {
+            result.putLong( testRunId );
+        }
+        result.put( (byte) ':' );
+    }
+
+    public void encodeHeader( ByteBuffer result, E operation )
     {
         result.put( (byte) ':' );
         result.put( getEncodedMagicNumber() );
@@ -89,15 +107,6 @@ public abstract class AbstractStreamEncoder<E extends Enum<E>>
         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) ':' );
-        }
     }
 
     public void encodeCharset( ByteBuffer result )
@@ -141,9 +150,21 @@ public abstract class AbstractStreamEncoder<E extends Enum<E>>
         result.put( (byte) ':' );
     }
 
-    public void encode( CharsetEncoder encoder, ByteBuffer result, E operation, RunMode runMode, String... messages )
+    public void encode( CharsetEncoder encoder, ByteBuffer result, E operation, RunMode runMode, Long testRunId,
+                        String... messages )
+    {
+        encodeHeader( result, operation, runMode, testRunId );
+        encodeStringData( result, encoder, messages );
+    }
+
+    public void encode( CharsetEncoder encoder, ByteBuffer result, E operation, String... messages )
+    {
+        encodeHeader( result, operation );
+        encodeStringData( result, encoder, messages );
+    }
+
+    private void encodeStringData( ByteBuffer result, CharsetEncoder encoder, String... messages )
     {
-        encodeHeader( result, operation, runMode );
         encodeCharset( result );
         for ( String message : messages )
         {
@@ -152,7 +173,7 @@ public abstract class AbstractStreamEncoder<E extends Enum<E>>
     }
 
     public int estimateBufferLength( int opcodeLength, RunMode runMode, CharsetEncoder encoder,
-                                     int integersCounter, String... strings )
+                                     int integersCounter, int longsCounter, String... strings )
     {
         assert !( encoder == null && strings.length != 0 );
 
@@ -173,12 +194,15 @@ public abstract class AbstractStreamEncoder<E extends Enum<E>>
         }
 
         // one byte (0x00 if NULL) + 4 bytes for integer + one delimiter character ':'
-        int lengthOfData = ( 1 + 1 + 4 ) * integersCounter;
+        int lengthOfData = ( 1 + 4 + 1 ) * integersCounter;
+
+        // one byte (0x00 if NULL) + 8 bytes for long + one delimiter character ':'
+        lengthOfData += ( 1 + 8 + 1 ) * longsCounter;
 
         for ( String string : strings )
         {
             String s = nonNull( string );
-            // 4 bytes of string length + one delimiter character ':' + <string> + one delimiter character ':'
+            // 4 bytes of length of the string + one delimiter character ':' + <string> + one delimiter character ':'
             lengthOfData += 4 + 1 + (int) ceil( encoder.maxBytesPerChar() * s.length() ) + 1;
         }
 
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/SegmentType.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/SegmentType.java
index f81d2ce..97932f1 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/SegmentType.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/SegmentType.java
@@ -25,6 +25,7 @@ package org.apache.maven.surefire.api.stream;
 public enum SegmentType
 {
     RUN_MODE,
+    TEST_RUN_ID,
     STRING_ENCODING,
     DATA_STRING,
     DATA_INTEGER,
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoderTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoderTest.java
index 2dd9c72..2ff06ea 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoderTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoderTest.java
@@ -39,7 +39,6 @@ import org.apache.maven.surefire.api.booter.Constants;
 import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
 import org.apache.maven.surefire.api.event.Event;
 import org.apache.maven.surefire.api.fork.ForkNodeArguments;
-import org.apache.maven.surefire.api.report.RunMode;
 import org.apache.maven.surefire.api.stream.AbstractStreamDecoder.MalformedFrameException;
 import org.apache.maven.surefire.api.stream.AbstractStreamDecoder.Memento;
 import org.apache.maven.surefire.api.stream.AbstractStreamDecoder.Segment;
@@ -686,9 +685,7 @@ public class AbstractStreamDecoderTest
 
         @Nonnull
         @Override
-        protected Event toMessage(
-            @Nonnull ForkedProcessEventType messageType, RunMode runMode,
-            @Nonnull Memento memento ) throws MalformedFrameException
+        protected Event toMessage( @Nonnull ForkedProcessEventType messageType, @Nonnull Memento memento )
         {
             return null;
         }
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoderTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoderTest.java
index bec5a58..a94ce76 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoderTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/api/stream/AbstractStreamEncoderTest.java
@@ -69,109 +69,109 @@ public class AbstractStreamEncoderTest
         Encoder streamEncoder = new Encoder( new DummyChannel() );
         CharsetEncoder encoder = streamEncoder.newCharsetEncoder();
 
-        // :maven-surefire-event:8:sys-prop:10:normal-run:5:UTF-8:0001:kkk:0001:vvv:
+        // :maven-surefire-event:8:sys-prop:10:normal-run:1:5:UTF-8:0003:kkk:0003:vvv:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_SYSPROPS.getOpcodeBinary().length, NORMAL_RUN,
-            encoder, 0, "k", "v" ) )
-            .isEqualTo( 72 );
+            encoder, 0, 1, "k", "v" ) )
+            .isEqualTo( 82 );
 
-        // :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:
+        // :maven-surefire-event:16:testset-starting:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TESTSET_STARTING.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 149 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 159 );
 
-        // :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:
+        // :maven-surefire-event:17:testset-completed:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TESTSET_COMPLETED.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 150 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 160 );
 
-        // :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:
+        // :maven-surefire-event:13:test-starting:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_STARTING.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 146 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 156 );
 
-        // :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:
+        // :maven-surefire-event:14:test-succeeded:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_SUCCEEDED.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 147 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 157 );
 
-        // :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:
+        // :maven-surefire-event:11:test-failed:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_FAILED.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 144 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 154 );
 
-        // :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:
+        // :maven-surefire-event:12:test-skipped:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_SKIPPED.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 145 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 155 );
 
-        // :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:
+        // :maven-surefire-event:10:test-error:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_ERROR.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 143 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 153 );
 
-        // :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:
+        // :maven-surefire-event:23:test-assumption-failure:10:normal-run:1:5:UTF-8:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:0003:sss:X0003:0003:sss:0003:sss:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_TEST_ASSUMPTIONFAILURE.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
-            .isEqualTo( 156 );
+            NORMAL_RUN, encoder, 1, 1, "s", "s", "s", "s", "s", "s", "s", "s", "s" ) )
+            .isEqualTo( 166 );
 
-        // :maven-surefire-event:14:std-out-stream:10:normal-run:5:UTF-8:0001:sss:
+        // :maven-surefire-event:14:std-out-stream:10:normal-run:1:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_STDOUT.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 0, "s" ) )
-            .isEqualTo( 69 );
+            NORMAL_RUN, encoder, 0, 1, "s" ) )
+            .isEqualTo( 79 );
 
-        // :maven-surefire-event:23:std-out-stream-new-line:10:normal-run:5:UTF-8:0001:sss:
+        // :maven-surefire-event:23:std-out-stream-new-line:10:normal-run:1:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_STDOUT_NEW_LINE.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 0, "s" ) )
-            .isEqualTo( 78 );
+            NORMAL_RUN, encoder, 0, 1, "s" ) )
+            .isEqualTo( 88 );
 
-        // :maven-surefire-event:14:std-err-stream:10:normal-run:5:UTF-8:0001:sss:
+        // :maven-surefire-event:14:std-err-stream:10:normal-run:1:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_STDERR.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 0, "s" ) )
-            .isEqualTo( 69 );
+            NORMAL_RUN, encoder, 0, 1, "s" ) )
+            .isEqualTo( 79 );
 
-        // :maven-surefire-event:23:std-err-stream-new-line:10:normal-run:5:UTF-8:0001:sss:
+        // :maven-surefire-event:23:std-err-stream-new-line:10:normal-run:1:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_STDERR_NEW_LINE.getOpcodeBinary().length,
-            NORMAL_RUN, encoder, 0, "s" ) )
-            .isEqualTo( 78 );
+            NORMAL_RUN, encoder, 0, 1, "s" ) )
+            .isEqualTo( 88 );
 
-        // :maven-surefire-event:16:console-info-log:5:UTF-8:0001:sss:
+        // :maven-surefire-event:16:console-info-log:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_CONSOLE_INFO.getOpcodeBinary().length,
-            null, encoder, 0, "s" ) )
+            null, encoder, 0, 0, "s" ) )
             .isEqualTo( 58 );
 
-        // :maven-surefire-event:17:console-debug-log:5:UTF-8:0001:sss:
+        // :maven-surefire-event:17:console-debug-log:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_CONSOLE_DEBUG.getOpcodeBinary().length,
-            null, encoder, 0, "s" ) )
+            null, encoder, 0, 0, "s" ) )
             .isEqualTo( 59 );
 
-        // :maven-surefire-event:19:console-warning-log:5:UTF-8:0001:sss:
+        // :maven-surefire-event:19:console-warning-log:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_CONSOLE_WARNING.getOpcodeBinary().length,
-            null, encoder, 0, "s" ) )
+            null, encoder, 0, 0, "s" ) )
             .isEqualTo( 61 );
 
-        // :maven-surefire-event:17:console-error-log:5:UTF-8:0001:sss:
+        // :maven-surefire-event:17:console-error-log:5:UTF-8:0003:sss:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_CONSOLE_ERROR.getOpcodeBinary().length,
-            null, encoder, 0, "s" ) )
+            null, encoder, 0, 0, "s" ) )
             .isEqualTo( 59 );
 
         // :maven-surefire-event:3:bye:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_BYE.getOpcodeBinary().length,
-            null, null, 0 ) )
+            null, null, 0, 0 ) )
             .isEqualTo( 28 );
 
         // :maven-surefire-event:17:stop-on-next-test:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_STOP_ON_NEXT_TEST.getOpcodeBinary().length,
-            null, null, 0 ) )
+            null, null, 0, 0 ) )
             .isEqualTo( 42 );
 
         // :maven-surefire-event:9:next-test:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_NEXT_TEST.getOpcodeBinary().length,
-            null, null, 0 ) )
+            null, null, 0, 0 ) )
             .isEqualTo( 34 );
 
         // :maven-surefire-event:14:jvm-exit-error:
         assertThat( streamEncoder.estimateBufferLength( BOOTERCODE_JVM_EXIT_ERROR.getOpcodeBinary().length,
-            null, null, 0 ) )
+            null, null, 0, 0 ) )
             .isEqualTo( 39 );
     }
 
@@ -180,12 +180,13 @@ public class AbstractStreamEncoderTest
     {
         Encoder streamEncoder = new Encoder( new DummyChannel() );
         ByteBuffer result = ByteBuffer.allocate( 128 );
-        streamEncoder.encodeHeader( result, BOOTERCODE_TEST_ERROR, NORMAL_RUN );
+        streamEncoder.encodeHeader( result, BOOTERCODE_TEST_ERROR, NORMAL_RUN, 1L );
         assertThat( toString( result ) )
-            .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:" );
+            .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10
+                + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" );
 
         result = ByteBuffer.allocate( 1024 );
-        streamEncoder.encodeHeader( result, BOOTERCODE_CONSOLE_ERROR, null );
+        streamEncoder.encodeHeader( result, BOOTERCODE_CONSOLE_ERROR );
         streamEncoder.encodeCharset( result );
         assertThat( toString( result ) )
             .isEqualTo( ":maven-surefire-event:" + (char) 17 + ":console-error-log:" + (char) 5 + ":UTF-8:" );
@@ -196,10 +197,11 @@ public class AbstractStreamEncoderTest
     {
         Encoder streamEncoder = new Encoder( new DummyChannel() );
         ByteBuffer result = ByteBuffer.allocate( 128 );
-        streamEncoder.encode( streamEncoder.newCharsetEncoder(), result, BOOTERCODE_STDOUT, NORMAL_RUN, null, "msg" );
+        streamEncoder.encode( streamEncoder.newCharsetEncoder(), result, BOOTERCODE_STDOUT, NORMAL_RUN, 1L, "msg" );
         assertThat( toString( result ) )
             .isEqualTo( ":maven-surefire-event:\u000e:std-out-stream:"
-                + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0001:\u0000:\u0000\u0000\u0000\u0003:msg:" );
+                + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001"
+                + ":\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:" );
     }
 
     @Test
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java
index b3fc7d7..b4a234d 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java
@@ -43,7 +43,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
 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;
@@ -65,7 +64,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.report.RunMode.NORMAL_RUN;
 
 /**
  * magic number : opcode : run mode [: opcode specific data]*
@@ -77,45 +75,20 @@ import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
 @SuppressWarnings( "checkstyle:linelength" )
 public class EventChannelEncoder extends EventEncoder implements MasterProcessChannelEncoder
 {
-    private final RunMode runMode;
     private final AtomicBoolean trouble = new AtomicBoolean();
     private volatile boolean onExit;
 
     /**
-     * The encoder for events and normal test mode.
+     * The encoder for events.
      *
      * @param out     the channel available for writing the events
      */
     public EventChannelEncoder( @Nonnull WritableBufferedByteChannel out )
     {
-        this( out, NORMAL_RUN );
-    }
-
-    /**
-     * The encoder for events and any test mode.
-     *
-     * @param out     the channel available for writing the events
-     * @param runMode run mode
-     */
-    public EventChannelEncoder( @Nonnull WritableBufferedByteChannel out, @Nonnull RunMode runMode )
-    {
         super( out );
-        this.runMode = requireNonNull( runMode );
-    }
-
-    /*@Override
-    public MasterProcessChannelEncoder asRerunMode() // todo apply this and rework providers
-    {
-        return new EventChannelEncoder( streamEncoder, RERUN_TEST_AFTER_FAILURE );
     }
 
     @Override
-    public MasterProcessChannelEncoder asNormalMode()
-    {
-        return new EventChannelEncoder( streamEncoder, NORMAL_RUN );
-    }*/
-
-    @Override
     public boolean checkError()
     {
         return trouble.get();
@@ -128,7 +101,7 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
         write( ByteBuffer.wrap( new byte[] {'\n'} ), true );
     }
 
-    private void encodeSystemProperties( Map<String, String> sysProps, RunMode rm, Long testRunId )
+    void encodeSystemProperties( Map<String, String> sysProps, RunMode runMode, Long testRunId )
     {
         CharsetEncoder encoder = newCharsetEncoder();
         ByteBuffer result = null;
@@ -139,11 +112,11 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
             String value = entry.getValue();
 
             int bufferLength =
-                estimateBufferLength( BOOTERCODE_SYSPROPS.getOpcode().length(), runMode, encoder, 0, key, value );
+                estimateBufferLength( BOOTERCODE_SYSPROPS.getOpcode().length(), runMode, encoder, 0, 1, key, value );
             result = result != null && result.capacity() >= bufferLength ? result : ByteBuffer.allocate( bufferLength );
             ( (Buffer) result ).clear();
-            // :maven-surefire-event:sys-prop:rerun-test-after-failure:UTF-8:<integer>:<key>:<integer>:<value>:
-            encode( encoder, result, BOOTERCODE_SYSPROPS, runMode, key, value );
+            // :maven-surefire-event:sys-prop:<runMode>:<testRunId>:UTF-8:<integer>:<key>:<integer>:<value>:
+            encode( encoder, result, BOOTERCODE_SYSPROPS, runMode, testRunId, key, value );
             boolean sync = !it.hasNext();
             write( result, sync );
         }
@@ -152,50 +125,50 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
     @Override
     public void testSetStarting( TestSetReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TESTSET_STARTING, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testSetCompleted( TestSetReportEntry reportEntry, boolean trimStackTraces )
     {
-        encodeSystemProperties( reportEntry.getSystemProperties(), null, null ); // todo in next commit
-        encode( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry, trimStackTraces, true );
+        encodeSystemProperties( reportEntry.getSystemProperties(), reportEntry.getRunMode(), reportEntry.getTestRunId() );
+        encode( BOOTERCODE_TESTSET_COMPLETED, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testStarting( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_STARTING, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_STARTING, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testSucceeded( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_SUCCEEDED, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testFailed( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_FAILED, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_FAILED, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testSkipped( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_SKIPPED, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testError( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_ERROR, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_ERROR, reportEntry, trimStackTraces, true );
     }
 
     @Override
     public void testAssumptionFailure( ReportEntry reportEntry, boolean trimStackTraces )
     {
-        encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry, trimStackTraces, true );
+        encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, reportEntry, trimStackTraces, true );
     }
 
     @Override
@@ -207,19 +180,19 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
         ForkedProcessEventType event =
             stdout ? ( newLine ? BOOTERCODE_STDOUT_NEW_LINE : BOOTERCODE_STDOUT )
                 : ( newLine ? BOOTERCODE_STDERR_NEW_LINE : BOOTERCODE_STDERR );
-        setOutErr( event, msg ); /*todo*/
+        setOutErr( event, reportEntry.getRunMode(), reportEntry.getTestRunId(), msg );
     }
 
-    private void setOutErr( ForkedProcessEventType eventType, String message )
+    private void setOutErr( ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message )
     {
-        ByteBuffer result = encodeMessage( eventType, runMode, message );
+        ByteBuffer result = encodeMessage( eventType, runMode, testRunId, message );
         write( result, false );
     }
 
     @Override
     public void consoleInfoLog( String message )
     {
-        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_INFO, null, message );
+        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_INFO, message );
         write( result, true );
     }
 
@@ -240,10 +213,10 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
     {
         CharsetEncoder encoder = newCharsetEncoder();
         String stackTrace = t == null ? null : ConsoleLoggerUtils.toString( t );
-        int bufferMaxLength = estimateBufferLength( BOOTERCODE_CONSOLE_ERROR.getOpcode().length(), null, encoder, 0,
+        int bufferMaxLength = estimateBufferLength( BOOTERCODE_CONSOLE_ERROR.getOpcode().length(), null, encoder, 0, 0,
             message, stackTrace );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, BOOTERCODE_CONSOLE_ERROR, null );
+        encodeHeader( result, BOOTERCODE_CONSOLE_ERROR );
         encodeCharset( result );
         encode( encoder, result, message, null, stackTrace );
         write( result, true );
@@ -258,14 +231,14 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
     @Override
     public void consoleDebugLog( String message )
     {
-        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_DEBUG, null, message );
+        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_DEBUG, message );
         write( result, true );
     }
 
     @Override
     public void consoleWarningLog( String message )
     {
-        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_WARNING, null, message );
+        ByteBuffer result = encodeMessage( BOOTERCODE_CONSOLE_WARNING, message );
         write( result, true );
     }
 
@@ -298,30 +271,30 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
     {
         CharsetEncoder encoder = newCharsetEncoder();
         StackTrace stackTraceWrapper = new StackTrace( stackTraceWriter, trimStackTraces );
-        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), null, encoder, 0,
+        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), null, encoder, 0, 0,
             stackTraceWrapper.message, stackTraceWrapper.smartTrimmedStackTrace, stackTraceWrapper.stackTrace );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
 
-        encodeHeader( result, eventType, null );
+        encodeHeader( result, eventType );
         encodeCharset( result );
         encode( encoder, result, stackTraceWrapper );
         write( result, sync );
     }
 
     // example
-    // :maven-surefire-event:testset-starting:rerun-test-after-failure:UTF-8:<integer>:SourceName:<integer>:SourceText:<integer>:Name:<integer>:NameText:<integer>:Group:<integer>:Message:<integer>:ElapsedTime:<integer>:LocalizedMessage:<integer>:SmartTrimmedStackTrace:<integer>:toStackTrace( stw, trimStackTraces ):<integer>:
-    private void encode( ForkedProcessEventType operation, RunMode runMode, ReportEntry reportEntry,
+    // :maven-surefire-event:testset-starting:rerun-test-after-failure:1:5:UTF-8:<integer>:SourceName:<integer>:SourceText:<integer>:Name:<integer>:NameText:<integer>:Group:<integer>:Message:<integer>:ElapsedTime:<integer>:LocalizedMessage:<integer>:SmartTrimmedStackTrace:<integer>:toStackTrace( stw, trimStackTraces ):<integer>:
+    private void encode( ForkedProcessEventType operation, ReportEntry reportEntry,
                          boolean trimStackTraces, @SuppressWarnings( "SameParameterValue" ) boolean sync )
     {
-        ByteBuffer result = encode( operation, runMode, reportEntry, trimStackTraces );
+        ByteBuffer result = encode( operation, reportEntry, trimStackTraces );
         write( result, sync );
     }
 
     private void encodeOpcode( ForkedProcessEventType eventType, boolean sync )
     {
-        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), null, null, 0 );
+        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), null, null, 0, 0 );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encodeHeader( result, eventType, null );
+        encodeHeader( result, eventType );
         write( result, sync );
     }
 
@@ -387,21 +360,20 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
      * <li>{@link ForkedProcessEventType#BOOTERCODE_TEST_ASSUMPTIONFAILURE}.</li>
      * </ul>
      */
-    ByteBuffer encode( ForkedProcessEventType operation, RunMode runMode, ReportEntry reportEntry,
-                               boolean trimStackTraces )
+    ByteBuffer encode( ForkedProcessEventType operation, ReportEntry reportEntry, boolean trimStackTraces )
     {
         StackTrace stackTraceWrapper = new StackTrace( reportEntry.getStackTraceWriter(), trimStackTraces );
 
         CharsetEncoder encoder = newCharsetEncoder();
 
-        int bufferMaxLength = estimateBufferLength( operation.getOpcode().length(), runMode, encoder, 1,
-            reportEntry.getSourceName(), reportEntry.getSourceText(), reportEntry.getName(), reportEntry.getNameText(),
-            reportEntry.getGroup(), reportEntry.getMessage(), stackTraceWrapper.message,
+        int bufferMaxLength = estimateBufferLength( operation.getOpcode().length(), reportEntry.getRunMode(), encoder,
+            1, 1, reportEntry.getSourceName(), reportEntry.getSourceText(), reportEntry.getName(),
+            reportEntry.getNameText(), reportEntry.getGroup(), reportEntry.getMessage(), stackTraceWrapper.message,
             stackTraceWrapper.smartTrimmedStackTrace, stackTraceWrapper.stackTrace );
 
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
 
-        encodeHeader( result, operation, runMode );
+        encodeHeader( result, operation, reportEntry.getRunMode(), reportEntry.getTestRunId() );
         encodeCharset( result );
 
         encodeString( encoder, result, reportEntry.getSourceName() );
@@ -417,12 +389,22 @@ public class EventChannelEncoder extends EventEncoder implements MasterProcessCh
         return result;
     }
 
-    ByteBuffer encodeMessage( ForkedProcessEventType eventType, RunMode runMode, String message )
+    ByteBuffer encodeMessage( ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message )
+    {
+        CharsetEncoder encoder = newCharsetEncoder();
+        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), runMode, encoder, 0,
+            testRunId == null ? 0 : 1, message );
+        ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
+        encode( encoder, result, eventType, runMode, testRunId, message );
+        return result;
+    }
+
+    ByteBuffer encodeMessage( ForkedProcessEventType eventType, String message )
     {
         CharsetEncoder encoder = newCharsetEncoder();
-        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), runMode, encoder, 0, message );
+        int bufferMaxLength = estimateBufferLength( eventType.getOpcode().length(), null, encoder, 0, 0, message );
         ByteBuffer result = ByteBuffer.allocate( bufferMaxLength );
-        encode( encoder, result, eventType, runMode, message );
+        encode( encoder, result, eventType, message );
         return result;
     }
 
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/stream/CommandDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/stream/CommandDecoder.java
index 76148b0..4a7e257 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/stream/CommandDecoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/stream/CommandDecoder.java
@@ -23,7 +23,6 @@ import org.apache.maven.surefire.api.booter.Command;
 import org.apache.maven.surefire.api.booter.MasterProcessCommand;
 import org.apache.maven.surefire.api.booter.Shutdown;
 import org.apache.maven.surefire.api.fork.ForkNodeArguments;
-import org.apache.maven.surefire.api.report.RunMode;
 import org.apache.maven.surefire.api.stream.AbstractStreamDecoder;
 import org.apache.maven.surefire.api.stream.MalformedChannelException;
 import org.apache.maven.surefire.api.stream.SegmentType;
@@ -46,10 +45,8 @@ import static org.apache.maven.surefire.api.booter.Command.toRunClass;
 import static org.apache.maven.surefire.api.booter.Command.toShutdown;
 import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER_FOR_COMMANDS_BYTES;
 import static org.apache.maven.surefire.api.booter.MasterProcessCommand.COMMAND_TYPES;
-import static org.apache.maven.surefire.api.report.RunMode.RUN_MODES;
 import static org.apache.maven.surefire.api.stream.SegmentType.DATA_STRING;
 import static org.apache.maven.surefire.api.stream.SegmentType.END_OF_FRAME;
-import static org.apache.maven.surefire.api.stream.SegmentType.RUN_MODE;
 import static org.apache.maven.surefire.api.stream.SegmentType.STRING_ENCODING;
 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
 
@@ -65,13 +62,6 @@ public class CommandDecoder extends AbstractStreamDecoder<Command, MasterProcess
         END_OF_FRAME
     };
 
-    private static final SegmentType[] COMMAND_WITH_RUNNABLE_STRING = new SegmentType[] {
-        RUN_MODE,
-        STRING_ENCODING,
-        DATA_STRING,
-        END_OF_FRAME
-    };
-
     private static final SegmentType[] COMMAND_WITH_ONE_STRING = new SegmentType[] {
         STRING_ENCODING,
         DATA_STRING,
@@ -100,14 +90,11 @@ public class CommandDecoder extends AbstractStreamDecoder<Command, MasterProcess
                 throw new MalformedFrameException( memento.getLine().getPositionByteBuffer(),
                     memento.getByteBuffer().position() );
             }
-            RunMode runMode = null;
+
             for ( SegmentType segmentType : nextSegmentType( commandType ) )
             {
                 switch ( segmentType )
                 {
-                    case RUN_MODE:
-                        runMode = RUN_MODES.get( readSegment( memento ) );
-                        break;
                     case STRING_ENCODING:
                         memento.setCharset( readCharset( memento ) );
                         break;
@@ -120,7 +107,7 @@ public class CommandDecoder extends AbstractStreamDecoder<Command, MasterProcess
                     case END_OF_FRAME:
                         memento.getLine().setPositionByteBuffer( memento.getByteBuffer().position() );
                         memento.getLine().clear();
-                        return toMessage( commandType, runMode, memento );
+                        return toMessage( commandType, memento );
                     default:
                         memento.getLine().setPositionByteBuffer( NO_POSITION );
                         arguments.dumpStreamText( "Unknown enum ("
@@ -179,7 +166,6 @@ public class CommandDecoder extends AbstractStreamDecoder<Command, MasterProcess
             case TEST_SET_FINISHED:
                 return COMMAND_WITHOUT_DATA;
             case RUN_CLASS:
-                return COMMAND_WITH_RUNNABLE_STRING;
             case SHUTDOWN:
                 return COMMAND_WITH_ONE_STRING;
             default:
@@ -189,7 +175,7 @@ public class CommandDecoder extends AbstractStreamDecoder<Command, MasterProcess
 
     @Nonnull
     @Override
-    protected Command toMessage( @Nonnull MasterProcessCommand commandType, RunMode runMode, @Nonnull Memento memento )
+    protected Command toMessage( @Nonnull MasterProcessCommand commandType, @Nonnull Memento memento )
         throws MalformedFrameException
     {
         switch ( commandType )
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 0f310c9..7fecd46 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -259,8 +259,6 @@ public class CommandReaderTest
             .append( ":maven-surefire-command:" )
             .append( (char) 13 )
             .append( ":run-testclass:" )
-            .append( (char) 10 )
-            .append( ":normal-run:" )
             .append( (char) 5 )
             .append( ":UTF-8:" )
             .append( (char) ( clsLength >> 24 ) )
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/CommandChannelDecoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/CommandChannelDecoderTest.java
index 7307460..d6c6776 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/CommandChannelDecoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/CommandChannelDecoderTest.java
@@ -89,8 +89,6 @@ public class CommandChannelDecoderTest
             .append( ":maven-surefire-command:" )
             .append( (char) 13 )
             .append( ":run-testclass:" )
-            .append( (char) 10 )
-            .append( ":normal-run:" )
             .append( (char) 5 )
             .append( ":UTF-8:" )
             .append( (char) 0 )
@@ -312,6 +310,7 @@ public class CommandChannelDecoderTest
     public void testBinaryCommandStream() throws Exception
     {
         InputStream commands = getClass().getResourceAsStream( "/binary-commands/75171711-encoder.bin" );
+        assertThat( commands ).isNotNull();
         ConsoleLoggerMock logger = new ConsoleLoggerMock( true, true, true, true );
         ForkNodeArguments args = new ForkNodeArgumentsMock( logger, new File( "" ) );
         CommandChannelDecoder decoder = new CommandChannelDecoder( newChannel( commands ), args );
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java
index 15965e4..5b28d3a 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java
@@ -25,6 +25,7 @@ import org.apache.maven.surefire.api.report.SafeThrowable;
 import org.apache.maven.surefire.api.report.StackTraceWriter;
 import org.apache.maven.surefire.api.report.TestOutputReportEntry;
 import org.apache.maven.surefire.api.report.TestSetReportEntry;
+import org.apache.maven.surefire.api.util.internal.ObjectUtils;
 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
 import org.junit.Test;
 
@@ -78,6 +79,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -88,13 +91,15 @@ public class EventChannelEncoderTest
 
         Stream out = Stream.newStream();
         EventChannelEncoder encoder = new EventChannelEncoder( newBufferedChannel( out ) );
-        ByteBuffer encoded = encoder.encode( BOOTERCODE_TEST_ERROR, NORMAL_RUN, reportEntry, false );
+        ByteBuffer encoded = encoder.encode( BOOTERCODE_TEST_ERROR, 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( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -143,13 +148,15 @@ public class EventChannelEncoderTest
 
         out = Stream.newStream();
         encoder = new EventChannelEncoder( newBufferedChannel( out ) );
-        encoded = encoder.encode( BOOTERCODE_TEST_ERROR, NORMAL_RUN, reportEntry, true );
+        encoded = encoder.encode( BOOTERCODE_TEST_ERROR, 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( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -205,6 +212,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":testset-starting:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -259,6 +268,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":testset-starting:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -322,6 +333,8 @@ public class EventChannelEncoderTest
         Map<String, String> props = systemProps();
 
         TestSetReportEntry reportEntry = mock( TestSetReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -344,6 +357,8 @@ public class EventChannelEncoderTest
             expectedFrame.write( ":sys-prop:".getBytes() );
             expectedFrame.write( 10 );
             expectedFrame.write( ":normal-run:".getBytes() );
+            expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+            expectedFrame.write( ":".getBytes() );
             expectedFrame.write( 5 );
             expectedFrame.write( ":UTF-8:".getBytes() );
             int[] k = toBytes( entry.getKey().length() );
@@ -369,6 +384,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":testset-completed:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -431,6 +448,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -450,6 +469,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-starting:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -511,6 +532,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -529,6 +552,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-succeeded:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -590,6 +615,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -608,6 +635,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-failed:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -668,6 +697,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -686,6 +717,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-skipped:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -746,6 +779,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( ELAPSED_TIME );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -763,6 +798,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-error:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -823,6 +860,8 @@ public class EventChannelEncoderTest
         when( stackTraceWriter.writeTraceToString() ).thenReturn( null );
 
         ReportEntry reportEntry = mock( ReportEntry.class );
+        when( reportEntry.getRunMode() ).thenReturn( NORMAL_RUN );
+        when( reportEntry.getTestRunId() ).thenReturn( 1L );
         when( reportEntry.getElapsed() ).thenReturn( null );
         when( reportEntry.getGroup() ).thenReturn( "this group" );
         when( reportEntry.getMessage() ).thenReturn( "skipped test" );
@@ -841,6 +880,8 @@ public class EventChannelEncoderTest
         expectedFrame.write( ":test-assumption-failure:".getBytes( UTF_8 ) );
         expectedFrame.write( (byte) 10 );
         expectedFrame.write( ":normal-run:".getBytes( UTF_8 ) );
+        expectedFrame.write( "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001".getBytes() );
+        expectedFrame.write( ':' );
         expectedFrame.write( (byte) 5 );
         expectedFrame.write( ":UTF-8:".getBytes( UTF_8 ) );
         expectedFrame.write( new byte[] {0, 0, 0, 10} );
@@ -929,21 +970,26 @@ public class EventChannelEncoderTest
     public void testSendOpcode()
     {
         Channel channel = new Channel();
-        new EventChannelEncoder( channel ).testOutput( (TestOutputReportEntry) stdOut( "msg" ) );
+        new EventChannelEncoder( channel )
+            .testOutput( new TestOutputReportEntry( stdOut( "msg" ), NORMAL_RUN, 1L )  );
         assertThat( toString( channel.src ) )
                 .isEqualTo( ":maven-surefire-event:" + (char) 14 + ":std-out-stream:" + (char) 10 + ":normal-run:"
+                    + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
                     + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:" );
 
         channel = new Channel();
-        new EventChannelEncoder( channel ).testOutput( stdErr( null ) );
+        new EventChannelEncoder( channel )
+            .testOutput( new TestOutputReportEntry( stdErr( null ), NORMAL_RUN, 1L ) );
         assertThat( toString( channel.src ) )
                 .isEqualTo( ":maven-surefire-event:" + (char) 14 + ":std-err-stream:" + (char) 10 + ":normal-run:"
+                    + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
                     + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0001:\u0000:" );
 
         ByteBuffer result = new EventChannelEncoder( new Channel() )
-            .encodeMessage( BOOTERCODE_TEST_ERROR, NORMAL_RUN, "msg" );
+            .encodeMessage( BOOTERCODE_TEST_ERROR, NORMAL_RUN, 1L, "msg" );
         assertThat( toString( result ) )
             .isEqualTo( ":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:"
+                + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
                 + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:" );
     }
 
@@ -1115,11 +1161,12 @@ public class EventChannelEncoderTest
         WritableBufferedByteChannel channel = newBufferedChannel( out );
         EventChannelEncoder encoder = new EventChannelEncoder( channel );
 
-        encoder.testOutput( (TestOutputReportEntry) stdOut( "msg" ) );
+        encoder.testOutput( new TestOutputReportEntry( stdOut( "msg" ), NORMAL_RUN, 1L ) );
         channel.close();
 
         String expected = ":maven-surefire-event:\u000e:std-out-stream:"
-            + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
+            + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
 
         assertThat( new String( out.toByteArray(), UTF_8 ) )
                 .isEqualTo( expected );
@@ -1132,11 +1179,12 @@ public class EventChannelEncoderTest
         WritableBufferedByteChannel channel = newBufferedChannel( out );
         EventChannelEncoder encoder = new EventChannelEncoder( channel );
 
-        encoder.testOutput( stdOutln( "msg" ) );
+        encoder.testOutput( new TestOutputReportEntry( stdOutln( "msg" ), NORMAL_RUN, 1L ) );
         channel.close();
 
         String expected = ":maven-surefire-event:\u0017:std-out-stream-new-line:"
-            + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
+            + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
 
         assertThat( new String( out.toByteArray(), UTF_8 ) )
                 .isEqualTo( expected );
@@ -1149,11 +1197,12 @@ public class EventChannelEncoderTest
         WritableBufferedByteChannel channel = newBufferedChannel( out );
         EventChannelEncoder encoder = new EventChannelEncoder( channel );
 
-        encoder.testOutput( stdErr( "msg" ) );
+        encoder.testOutput( new TestOutputReportEntry( stdErr( "msg" ), NORMAL_RUN, 1L ) );
         channel.close();
 
         String expected = ":maven-surefire-event:\u000e:std-err-stream:"
-            + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
+            + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
 
         assertThat( new String( out.toByteArray(), UTF_8 ) )
                 .isEqualTo( expected );
@@ -1166,17 +1215,53 @@ public class EventChannelEncoderTest
         WritableBufferedByteChannel channel = newBufferedChannel( out );
         EventChannelEncoder encoder = new EventChannelEncoder( channel );
 
-        encoder.testOutput( stdErrln( "msg" ) );
+        encoder.testOutput( new TestOutputReportEntry( stdErrln( "msg" ), NORMAL_RUN, 1L ) );
         channel.close();
 
         String expected = ":maven-surefire-event:\u0017:std-err-stream-new-line:"
-            + (char) 10 + ":normal-run:\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
+            + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:"
+            + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:";
 
         assertThat( new String( out.toByteArray(), UTF_8 ) )
                 .isEqualTo( expected );
     }
 
     @Test
+    @SuppressWarnings( "checkstyle:innerassignment" )
+    public void shouldCountSameNumberOfSystemProperties() throws IOException
+    {
+        Stream stream = Stream.newStream();
+        WritableBufferedByteChannel channel = newBufferedChannel( stream );
+        EventChannelEncoder encoder = new EventChannelEncoder( channel );
+
+        Map<String, String> sysProps = ObjectUtils.systemProps();
+        encoder.encodeSystemProperties( sysProps, NORMAL_RUN, 1L );
+        channel.close();
+
+        for ( Entry<String, String> entry : sysProps.entrySet() )
+        {
+            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() );
+        }
+    }
+
+    @Test
     public void shouldHandleExit()
     {
         Stream out = Stream.newStream();
@@ -1220,7 +1305,7 @@ public class EventChannelEncoderTest
         Thread.currentThread().interrupt();
         try
         {
-            encoder.testOutput( (TestOutputReportEntry) stdOut( "msg" ) );
+            encoder.testOutput( new TestOutputReportEntry( stdOut( "msg" ), NORMAL_RUN, 2L )  );
             channel.close();
         }
         finally
@@ -1232,7 +1317,8 @@ public class EventChannelEncoderTest
 
         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:" );
+                    + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0002"
+                    + ":\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:" );
     }
 
     private static class Stream extends PrintStream
diff --git a/surefire-booter/src/test/resources/binary-commands/75171711-encoder.bin b/surefire-booter/src/test/resources/binary-commands/75171711-encoder.bin
index bbc337b..0a4ce71 100644
Binary files a/surefire-booter/src/test/resources/binary-commands/75171711-encoder.bin and b/surefire-booter/src/test/resources/binary-commands/75171711-encoder.bin differ
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java
index 2b124c6..92385e5 100644
--- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java
@@ -123,6 +123,7 @@ public class JUnitPlatformProvider
         try
         {
             RunListenerAdapter adapter = new RunListenerAdapter( reporterFactory.createTestReportListener() );
+            adapter.setRunMode( NORMAL_RUN );
             startCapture( adapter );
             setupJunitLogger();
             if ( forkTestSet instanceof TestsToRun )
@@ -169,7 +170,6 @@ public class JUnitPlatformProvider
 
     private void invokeAllTests( TestsToRun testsToRun, RunListenerAdapter adapter )
     {
-        adapter.setRunMode( NORMAL_RUN );
         try
         {
             execute( testsToRun, adapter );
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
index d4a57a9..5c38caa 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -130,6 +130,7 @@ public class JUnit4Provider
         {
             TestReportListener<TestOutputReportEntry> reporter = reporterFactory.createTestReportListener();
             JUnit4RunListener listener = new JUnit4RunListener( reporter );
+            listener.setRunMode( NORMAL_RUN );
 
             startCapture( listener );
             // startCapture() called in prior to setTestsToRun()
@@ -280,7 +281,6 @@ public class JUnit4Provider
             try
             {
                 notifier.asFailFast( isFailFast() );
-                runMode.setRunMode( NORMAL_RUN );
                 execute( clazz, notifier, hasMethodFilter ? createMethodFilter() : null );
             }
             finally