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 2017/04/17 11:54:57 UTC

maven-surefire git commit: [SUREFIRE-1364] Report XML should contain system properties of forked JVM

Repository: maven-surefire
Updated Branches:
  refs/heads/SUREFIRE-1364 [created] d303e625e


[SUREFIRE-1364] Report XML should contain system properties of forked JVM


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/d303e625
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/d303e625
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/d303e625

Branch: refs/heads/SUREFIRE-1364
Commit: d303e625e7cee4cd268da9ca9d0797b7598a65eb
Parents: 9c0025e
Author: Tibor17 <ti...@lycos.com>
Authored: Mon Apr 17 13:54:40 2017 +0200
Committer: Tibor17 <ti...@lycos.com>
Committed: Mon Apr 17 13:54:40 2017 +0200

----------------------------------------------------------------------
 .../surefire/StartupReportConfiguration.java    |  19 +--
 .../booterclient/ForkConfiguration.java         |   2 +-
 .../surefire/booterclient/ForkStarter.java      |  14 +-
 .../booterclient/output/ForkClient.java         |  32 +++--
 .../surefire/report/StatelessXmlReporter.java   |  35 +++--
 .../surefire/report/TestSetRunListener.java     |   9 +-
 .../surefire/report/WrappedReportEntry.java     |  26 +++-
 .../plugin/surefire/util/ImmutableMap.java      | 133 ------------------
 .../booterclient/ForkingRunListenerTest.java    |  35 +++--
 .../surefire/booterclient/MockReporter.java     |  12 +-
 .../report/StatelessXmlReporterTest.java        |   8 +-
 .../plugin/surefire/util/ImmutableMapTest.java  |  86 ------------
 .../apache/maven/surefire/JUnit4SuiteTest.java  |   4 +-
 .../surefire/booter/ForkingRunListener.java     |  24 ++--
 .../surefire/report/CategorizedReportEntry.java |  20 ++-
 .../maven/surefire/report/RunListener.java      |   4 +-
 .../surefire/report/SimpleReportEntry.java      |  36 ++++-
 .../surefire/report/TestSetReportEntry.java     |  35 +++++
 .../surefire/util/internal/ImmutableMap.java    | 134 +++++++++++++++++++
 .../surefire/util/internal/ObjectUtils.java     |   2 +-
 .../java/org/apache/maven/JUnit4SuiteTest.java  |   4 +-
 .../util/internal/ImmutableMapTest.java         |  86 ++++++++++++
 .../maven/surefire/junit4/MockReporter.java     |   5 +-
 .../maven/surefire/junit/JUnit3Provider.java    |  16 ++-
 .../maven/surefire/junit/JUnitTestSetTest.java  |  15 ++-
 .../maven/surefire/junit4/JUnit4Provider.java   |   4 +-
 .../junitcore/ConcurrentRunListener.java        |   5 +-
 .../junitcore/NonConcurrentRunListener.java     |  10 +-
 .../maven/surefire/junitcore/TestSet.java       |   5 +-
 .../apache/maven/surefire/testng/TestSuite.java |   8 +-
 30 files changed, 460 insertions(+), 368 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
index 482ce00..8482131 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
@@ -19,13 +19,6 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-import java.io.File;
-import java.io.PrintStream;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.maven.plugin.surefire.report.ConsoleOutputFileReporter;
 import org.apache.maven.plugin.surefire.report.DirectConsoleOutput;
 import org.apache.maven.plugin.surefire.report.FileReporter;
@@ -35,6 +28,11 @@ import org.apache.maven.plugin.surefire.report.WrappedReportEntry;
 import org.apache.maven.plugin.surefire.runorder.StatisticsReporter;
 
 import javax.annotation.Nonnull;
+import java.io.File;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import static org.apache.maven.plugin.surefire.report.ConsoleReporter.BRIEF;
 import static org.apache.maven.plugin.surefire.report.ConsoleReporter.PLAIN;
@@ -79,8 +77,6 @@ public final class StartupReportConfiguration
 
     private final String xsdSchemaLocation;
 
-    private final Properties testVmSystemProperties = new Properties();
-
     private final Map<String, Map<String, List<WrappedReportEntry>>> testClassMethodRunHistory
         = new ConcurrentHashMap<String, Map<String, List<WrappedReportEntry>>>();
 
@@ -213,11 +209,6 @@ public final class StartupReportConfiguration
         return statisticsFile;
     }
 
-    public Properties getTestVmSystemProperties()
-    {
-        return testVmSystemProperties;
-    }
-
     public boolean isTrimStackTrace()
     {
         return trimStackTrace;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
index c56453a..d0e9314 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkConfiguration.java
@@ -21,7 +21,7 @@ package org.apache.maven.plugin.surefire.booterclient;
 
 import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
-import org.apache.maven.plugin.surefire.util.ImmutableMap;
+import org.apache.maven.surefire.util.internal.ImmutableMap;
 import org.apache.maven.plugin.surefire.util.Relocator;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.surefire.booter.Classpath;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index c46cfb6..be634ff 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -57,7 +57,6 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
-import java.util.Properties;
 import java.util.Queue;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.Callable;
@@ -270,8 +269,7 @@ public class ForkStarter
         TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
         PropertiesWrapper props = new PropertiesWrapper( providerProperties );
         TestLessInputStream stream = builder.build();
-        Properties sysProps = startupReportConfiguration.getTestVmSystemProperties();
-        ForkClient forkClient = new ForkClient( forkedReporterFactory, sysProps, stream, log );
+        ForkClient forkClient = new ForkClient( forkedReporterFactory, stream, log );
         Thread shutdown = createImmediateShutdownHookThread( builder, providerConfiguration.getShutdown() );
         ScheduledFuture<?> ping = triggerPingTimerForShutdown( builder );
         try
@@ -347,10 +345,7 @@ public class ForkStarter
                     {
                         DefaultReporterFactory reporter = new DefaultReporterFactory( startupReportConfiguration, log );
                         defaultReporterFactories.add( reporter );
-
-                        Properties vmProps = startupReportConfiguration.getTestVmSystemProperties();
-
-                        ForkClient forkClient = new ForkClient( reporter, vmProps, testProvidingInputStream, log )
+                        ForkClient forkClient = new ForkClient( reporter, testProvidingInputStream, log )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -413,9 +408,8 @@ public class ForkStarter
                         DefaultReporterFactory forkedReporterFactory =
                             new DefaultReporterFactory( startupReportConfiguration, log );
                         defaultReporterFactories.add( forkedReporterFactory );
-                        Properties vmProps = startupReportConfiguration.getTestVmSystemProperties();
-                        ForkClient forkClient = new ForkClient( forkedReporterFactory, vmProps,
-                                                                      builder.getImmediateCommands(), log )
+                        ForkClient forkClient =
+                                new ForkClient( forkedReporterFactory, builder.getImmediateCommands(), log )
                         {
                             @Override
                             protected void stopOnNextTest()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
----------------------------------------------------------------------
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 b02ae54..dbee96a 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
@@ -27,22 +27,26 @@ import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
 import java.nio.ByteBuffer;
-import java.util.Properties;
+import java.util.Collections;
+import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicLong;
 
 import static java.lang.Integer.decode;
 import static java.lang.System.currentTimeMillis;
+import static java.util.Collections.unmodifiableMap;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_BYE;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_CONSOLE;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_DEBUG;
@@ -83,7 +87,7 @@ public class ForkClient
 
     private final DefaultReporterFactory defaultReporterFactory;
 
-    private final Properties testVmSystemProperties;
+    private final Map<String, String> testVmSystemProperties = new ConcurrentHashMap<String, String>();
 
     private final NotifiableTestStream notifiableTestStream;
 
@@ -108,11 +112,10 @@ public class ForkClient
     // prevents from printing same warning
     private boolean printedErrorStream;
 
-    public ForkClient( DefaultReporterFactory defaultReporterFactory, Properties testVmSystemProperties,
+    public ForkClient( DefaultReporterFactory defaultReporterFactory,
                        NotifiableTestStream notifiableTestStream, ConsoleLogger log )
     {
         this.defaultReporterFactory = defaultReporterFactory;
-        this.testVmSystemProperties = testVmSystemProperties;
         this.notifiableTestStream = notifiableTestStream;
         this.log = log;
     }
@@ -206,7 +209,7 @@ public class ForkClient
             case BOOTERCODE_TESTSET_COMPLETED:
                 testsInProgress.clear();
 
-                getTestSetReporter().testSetCompleted( createReportEntry( remaining ) );
+                getTestSetReporter().testSetCompleted( createReportEntry( remaining, testVmSystemProperties ) );
                 break;
             case BOOTERCODE_TEST_STARTING:
                 ReportEntry reportEntry = createReportEntry( remaining );
@@ -250,10 +253,7 @@ public class ForkClient
                 StringBuilder value = new StringBuilder();
                 unescapeString( key, remaining.substring( 0, keyEnd ) );
                 unescapeString( value, remaining.substring( keyEnd + 1 ) );
-                synchronized ( testVmSystemProperties )
-                {
-                    testVmSystemProperties.put( key.toString(), value.toString() );
-                }
+                testVmSystemProperties.put( key.toString(), value.toString() );
                 break;
             case BOOTERCODE_STDOUT:
                 writeTestOutput( remaining, true );
@@ -356,7 +356,12 @@ public class ForkClient
         return unescape( remaining );
     }
 
-    private ReportEntry createReportEntry( String untokenized )
+    private TestSetReportEntry createReportEntry( String untokenized )
+    {
+        return createReportEntry( untokenized, Collections.<String, String>emptyMap() );
+    }
+
+    private TestSetReportEntry createReportEntry( String untokenized, Map<String, String> systemProperties )
     {
         StringTokenizer tokens = new StringTokenizer( untokenized, "," );
         try
@@ -370,7 +375,7 @@ public class ForkClient
             final StackTraceWriter stackTraceWriter =
                     tokens.hasMoreTokens() ? deserializeStackTraceWriter( tokens ) : null;
 
-            return reportEntry( source, name, group, stackTraceWriter, elapsed, message );
+            return reportEntry( source, name, group, stackTraceWriter, elapsed, message, systemProperties );
         }
         catch ( RuntimeException e )
         {
@@ -399,6 +404,11 @@ public class ForkClient
         return stringBuffer.toString();
     }
 
+    public final Map<String, String> getTestVmSystemProperties()
+    {
+        return unmodifiableMap( testVmSystemProperties );
+    }
+
     /**
      * Used when getting reporters on the plugin side of a fork.
      * Used by testing purposes only. May not be volatile variable.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
index d10151a..bdce14b 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
@@ -39,7 +39,7 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
+import java.util.Map.Entry;
 import java.util.StringTokenizer;
 
 import static org.apache.maven.plugin.surefire.report.DefaultReporterFactory.TestResultType;
@@ -130,10 +130,10 @@ public class StatelessXmlReporter
 
             createTestSuiteElement( ppw, testSetReportEntry, testSetStats, testSetReportEntry.elapsedTimeAsString() );
 
-            showProperties( ppw );
+            showProperties( ppw, testSetReportEntry.getSystemProperties() );
 
             // Iterate through all the test methods in the test class
-            for ( Map.Entry<String, List<WrappedReportEntry>> entry : methodRunHistoryMap.entrySet() )
+            for ( Entry<String, List<WrappedReportEntry>> entry : methodRunHistoryMap.entrySet() )
             {
                 List<WrappedReportEntry> methodEntryList = entry.getValue();
                 if ( methodEntryList == null )
@@ -457,31 +457,26 @@ public class StatelessXmlReporter
      *
      * @param xmlWriter The test suite to report to
      */
-    private static void showProperties( XMLWriter xmlWriter )
+    private static void showProperties( XMLWriter xmlWriter, Map<String, String> systemProperties )
     {
         xmlWriter.startElement( "properties" );
-
-        Properties systemProperties = System.getProperties();
-
-        if ( systemProperties != null )
+        for ( final Entry<String, String> entry : systemProperties.entrySet() )
         {
-            for ( final String key : systemProperties.stringPropertyNames() )
-            {
-                String value = systemProperties.getProperty( key );
+            final String key = entry.getKey();
+            String value = entry.getValue();
 
-                if ( value == null )
-                {
-                    value = "null";
-                }
+            if ( value == null )
+            {
+                value = "null";
+            }
 
-                xmlWriter.startElement( "property" );
+            xmlWriter.startElement( "property" );
 
-                xmlWriter.addAttribute( "name", key );
+            xmlWriter.addAttribute( "name", key );
 
-                xmlWriter.addAttribute( "value", extraEscape( value, true ) );
+            xmlWriter.addAttribute( "value", extraEscape( value, true ) );
 
-                xmlWriter.endElement();
-            }
+            xmlWriter.endElement();
         }
         xmlWriter.endElement();
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
index 472586b..03ac891 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java
@@ -29,6 +29,7 @@ import org.apache.maven.plugin.surefire.runorder.StatisticsReporter;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 
 import static org.apache.maven.plugin.surefire.report.ReportEntryType.ERROR;
 import static org.apache.maven.plugin.surefire.report.ReportEntryType.FAILURE;
@@ -144,7 +145,7 @@ public class TestSetRunListener
     }
 
     @Override
-    public void testSetStarting( ReportEntry report )
+    public void testSetStarting( TestSetReportEntry report )
     {
         detailsForThis.testSetStart();
         consoleReporter.testSetStarting( report );
@@ -158,7 +159,7 @@ public class TestSetRunListener
     }
 
     @Override
-    public void testSetCompleted( ReportEntry report )
+    public void testSetCompleted( TestSetReportEntry report )
     {
         final WrappedReportEntry wrap = wrapTestSet( report );
         final List<String> testResults =
@@ -262,11 +263,11 @@ public class TestSetRunListener
         return new WrappedReportEntry( other, reportEntryType, estimatedElapsed, testStdOut, testStdErr );
     }
 
-    private WrappedReportEntry wrapTestSet( ReportEntry other )
+    private WrappedReportEntry wrapTestSet( TestSetReportEntry other )
     {
         return new WrappedReportEntry( other, null, other.getElapsed() != null
             ? other.getElapsed()
-            : detailsForThis.getElapsedSinceTestSetStart(), testStdOut, testStdErr );
+            : detailsForThis.getElapsedSinceTestSetStart(), testStdOut, testStdErr, other.getSystemProperties() );
     }
 
     public void close()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
index 439fdec..402fda0 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
@@ -21,14 +21,19 @@ package org.apache.maven.plugin.surefire.report;
 
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 
+import java.util.Collections;
+import java.util.Map;
+
+import static java.util.Collections.unmodifiableMap;
 import static org.apache.maven.surefire.util.internal.StringUtils.NL;
 
 /**
  * @author Kristian Rosenvold
  */
 public class WrappedReportEntry
-    implements ReportEntry
+    implements TestSetReportEntry
 {
     private final ReportEntry original;
 
@@ -40,15 +45,26 @@ public class WrappedReportEntry
 
     private final Utf8RecodingDeferredFileOutputStream stdErr;
 
+    private final Map<String, String> systemProperties;
+
     public WrappedReportEntry( ReportEntry original, ReportEntryType reportEntryType, Integer estimatedElapsed,
                                Utf8RecodingDeferredFileOutputStream stdout,
-                               Utf8RecodingDeferredFileOutputStream stdErr )
+                               Utf8RecodingDeferredFileOutputStream stdErr,
+                               Map<String, String> systemProperties )
     {
         this.original = original;
         this.reportEntryType = reportEntryType;
         this.elapsed = estimatedElapsed;
         this.stdout = stdout;
         this.stdErr = stdErr;
+        this.systemProperties = unmodifiableMap( systemProperties );
+    }
+
+    public WrappedReportEntry( ReportEntry original, ReportEntryType reportEntryType, Integer estimatedElapsed,
+                               Utf8RecodingDeferredFileOutputStream stdout,
+                               Utf8RecodingDeferredFileOutputStream stdErr )
+    {
+        this( original, reportEntryType, estimatedElapsed, stdout, stdErr, Collections.<String, String>emptyMap() );
     }
 
     @Override
@@ -171,4 +187,10 @@ public class WrappedReportEntry
     {
         return original.getNameWithGroup();
     }
+
+    @Override
+    public Map<String, String> getSystemProperties()
+    {
+        return systemProperties;
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ImmutableMap.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ImmutableMap.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ImmutableMap.java
deleted file mode 100644
index 576194d..0000000
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/ImmutableMap.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.apache.maven.plugin.surefire.util;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.AbstractMap;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Copies input map in {@link #ImmutableMap(Map) constructor}, and Entries are linked and thread-safe.
- * The map is immutable.
- *
- * @param <K> key
- * @param <V> value
- * @since 2.20
- */
-public final class ImmutableMap<K, V>
-        extends AbstractMap<K, V>
-{
-    private final Node<K, V> first;
-
-    public ImmutableMap( Map<K, V> map )
-    {
-        Node<K, V> first = null;
-        Node<K, V> previous = null;
-        for ( Entry<K, V> e : map.entrySet() )
-        {
-            Node<K, V> node = new Node<K, V>( e.getKey(), e.getValue() );
-            if ( first == null )
-            {
-                first = node;
-            }
-            else
-            {
-                previous.next = node;
-            }
-            previous = node;
-        }
-        this.first = first;
-    }
-
-    @Override
-    public Set<Entry<K, V>> entrySet()
-    {
-        Set<Entry<K, V>> entries = new LinkedHashSet<Entry<K, V>>();
-        Node<K, V> node = first;
-        while ( node != null )
-        {
-            entries.add( node );
-            node = node.next;
-        }
-        return Collections.<Entry<K, V>>unmodifiableSet( entries );
-    }
-
-    static final class Node<K, V>
-            implements Entry<K, V>
-    {
-        final K key;
-        final V value;
-        volatile Node<K, V> next;
-
-        Node( K key, V value )
-        {
-            this.key = key;
-            this.value = value;
-        }
-
-        @Override
-        public K getKey()
-        {
-            return key;
-        }
-
-        @Override
-        public V getValue()
-        {
-            return value;
-        }
-
-        @Override
-        public V setValue( V value )
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
-                return true;
-            }
-
-            if ( o == null || getClass() != o.getClass() )
-            {
-                return false;
-            }
-
-            Node<?, ?> node = (Node<?, ?>) o;
-
-            return getKey() != null ? getKey().equals( node.getKey() ) : node.getKey() == null
-                           && getValue() != null ? getValue().equals( node.getValue() ) : node.getValue() == null;
-
-        }
-
-        @Override
-        public int hashCode()
-        {
-            int result = getKey() != null ? getKey().hashCode() : 0;
-            result = 31 * result + ( getValue() != null ? getValue().hashCode() : 0 );
-            return result;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java
index 19356f5..12b2087 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
@@ -34,16 +34,16 @@ import org.apache.maven.surefire.report.ReporterException;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
+import org.hamcrest.MatcherAssert;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.nio.charset.Charset;
 import java.util.List;
-import java.util.Properties;
 import java.util.StringTokenizer;
 
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.is;
 
@@ -94,7 +94,7 @@ public class ForkingRunListenerTest
         throws ReporterException, IOException
     {
         final StandardTestRun standardTestRun = new StandardTestRun();
-        ReportEntry expected = createDefaultReportEntry();
+        TestSetReportEntry expected = createDefaultReportEntry();
         standardTestRun.run().testSetStarting( expected );
         standardTestRun.assertExpected( MockReporter.SET_STARTING, expected );
     }
@@ -103,7 +103,7 @@ public class ForkingRunListenerTest
         throws ReporterException, IOException
     {
         final StandardTestRun standardTestRun = new StandardTestRun();
-        ReportEntry expected = createDefaultReportEntry();
+        TestSetReportEntry expected = createDefaultReportEntry();
         standardTestRun.run().testSetCompleted( expected );
         standardTestRun.assertExpected( MockReporter.SET_COMPLETED, expected );
     }
@@ -221,27 +221,24 @@ public class ForkingRunListenerTest
         createForkingRunListener( defaultChannel );
 
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
-        final Properties testVmSystemProperties = new Properties();
         NullConsoleLogger log = new NullConsoleLogger();
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, testVmSystemProperties,
-                                                      new MockNotifiableTestStream(), log );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log );
 
-        forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) );
+        forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
-        assertThat( testVmSystemProperties.size(), is( greaterThan( 1 ) ) );
+        MatcherAssert.assertThat( forkStreamClient.getTestVmSystemProperties().size(), is( greaterThan( 1 ) ) );
     }
 
     public void testMultipleEntries()
         throws ReporterException, IOException
     {
-
         final StandardTestRun standardTestRun = new StandardTestRun();
         standardTestRun.run();
 
         reset();
         RunListener forkingReporter = createForkingRunListener( defaultChannel );
 
-        ReportEntry reportEntry = createDefaultReportEntry();
+        TestSetReportEntry reportEntry = createDefaultReportEntry();
         forkingReporter.testSetStarting( reportEntry );
         forkingReporter.testStarting( reportEntry );
         forkingReporter.testSucceeded( reportEntry );
@@ -249,10 +246,9 @@ public class ForkingRunListenerTest
 
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
         NullConsoleLogger log = new NullConsoleLogger();
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new Properties(),
-                                                      new MockNotifiableTestStream(), log );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log );
 
-        forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) );
+        forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
         final MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
         final List<String> events = reporter.getEvents();
@@ -276,20 +272,19 @@ public class ForkingRunListenerTest
                 .testSkipped( secondExpected );
 
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
-        Properties vmProps = new Properties();
         NotifiableTestStream notifiableTestStream = new MockNotifiableTestStream();
         NullConsoleLogger log = new NullConsoleLogger();
 
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, vmProps, notifiableTestStream, log );
-        forkStreamClient.consumeMultiLineContent( content.toString( "utf-8" ) );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log );
+        forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
         MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
         Assert.assertEquals( MockReporter.TEST_STARTING, reporter.getFirstEvent() );
         Assert.assertEquals( expected, reporter.getFirstData() );
         Assert.assertEquals( 1, reporter.getEvents().size() );
 
-        forkStreamClient = new ForkClient( providerReporterFactory, vmProps, notifiableTestStream, log );
-        forkStreamClient.consumeMultiLineContent( anotherContent.toString( "utf-8" ) );
+        forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log );
+        forkStreamClient.consumeMultiLineContent( anotherContent.toString( "UTF-8" ) );
         MockReporter reporter2 = (MockReporter) forkStreamClient.getReporter();
         Assert.assertEquals( MockReporter.TEST_SKIPPED, reporter2.getFirstEvent() );
         Assert.assertEquals( secondExpected, reporter2.getFirstData() );
@@ -357,7 +352,7 @@ public class ForkingRunListenerTest
         {
             TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
             NullConsoleLogger log = new NullConsoleLogger();
-            final ForkClient forkStreamClient = new ForkClient( providerReporterFactory, new Properties(),
+            final ForkClient forkStreamClient = new ForkClient( providerReporterFactory,
                                                                 new MockNotifiableTestStream(), log );
             forkStreamClient.consumeMultiLineContent( content.toString( ) );
             reporter = (MockReporter) forkStreamClient.getReporter();

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
index bfc8faf..150d443 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/MockReporter.java
@@ -19,13 +19,15 @@ package org.apache.maven.plugin.surefire.booterclient;
  * under the License.
  */
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.TestSetReportEntry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Internal tests use only.
@@ -66,14 +68,14 @@ public class MockReporter
     private final AtomicInteger testFailed = new AtomicInteger();
 
     @Override
-    public void testSetStarting( ReportEntry report )
+    public void testSetStarting( TestSetReportEntry report )
     {
         events.add( SET_STARTING );
         data.add( report );
     }
 
     @Override
-    public void testSetCompleted( ReportEntry report )
+    public void testSetCompleted( TestSetReportEntry report )
     {
         events.add( SET_COMPLETED );
         data.add( report );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
index c5b7a1e..445eaa8 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
@@ -38,6 +38,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
 import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 
 @SuppressWarnings( "ResultOfMethodCallIgnored" )
@@ -90,7 +91,7 @@ public class StatelessXmlReporterTest
 
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), getClass().getName(), 12 );
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null );
+            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
         stats.testSucceeded( testSetReportEntry );
         reporter.testSetCompleted( testSetReportEntry, stats );
 
@@ -105,7 +106,7 @@ public class StatelessXmlReporterTest
     {
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null );
+            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
         expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
@@ -177,7 +178,7 @@ public class StatelessXmlReporterTest
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
 
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null );
+            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
         expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
@@ -294,5 +295,4 @@ public class StatelessXmlReporterTest
     {
 
     }
-
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/ImmutableMapTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/ImmutableMapTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/ImmutableMapTest.java
deleted file mode 100644
index 8fcf2bb..0000000
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/ImmutableMapTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apache.maven.plugin.surefire.util;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.plugin.surefire.util.ImmutableMap.Node;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-/**
- * @since 2.20
- */
-public class ImmutableMapTest
-{
-    private ImmutableMap<String, String> map;
-
-    @Before
-    public void setUp() throws Exception
-    {
-        Map<String, String> backingMap = new HashMap<String, String>();
-        backingMap.put( "a", "1" );
-        backingMap.put( "x", null );
-        backingMap.put( "b", "2" );
-        backingMap.put( "c", "3" );
-        backingMap.put( "", "" );
-        backingMap.put( null, "1" );
-        map = new ImmutableMap<String, String>( backingMap );
-    }
-
-    @Test
-    public void testEntrySet() throws Exception
-    {
-        Set<Entry<String, String>> entries = map.entrySet();
-        assertThat( entries, hasSize( 6 ) );
-        assertThat( entries, hasItem( new Node<String, String>( "a", "1" ) ) );
-        assertThat( entries, hasItem( new Node<String, String>( "x", null ) ) );
-        assertThat( entries, hasItem( new Node<String, String>( "b", "2" ) ) );
-        assertThat( entries, hasItem( new Node<String, String>( "c", "3" ) ) );
-        assertThat( entries, hasItem( new Node<String, String>( "", "" ) ) );
-        assertThat( entries, hasItem( new Node<String, String>( null, "1" ) ) );
-    }
-
-    @Test
-    public void testGetter()
-    {
-        assertThat( map.size(), is( 6 ) );
-        assertThat( map.get( "a" ), is( "1" ) );
-        assertThat( map.get( "x" ), is( (String) null ) );
-        assertThat( map.get( "b" ), is( "2" ) );
-        assertThat( map.get( "c" ), is( "3" ) );
-        assertThat( map.get( "" ), is( "" ) );
-        assertThat( map.get( null ), is( "1" ) );
-    }
-
-    @Test( expected = UnsupportedOperationException.class )
-    public void shouldNotModifyEntries()
-    {
-        map.entrySet().clear();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index 9fb45bf..f7cec19 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -36,7 +36,6 @@ import org.apache.maven.plugin.surefire.report.WrappedReportEntryTest;
 import org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest;
 import org.apache.maven.plugin.surefire.util.DependenciesScannerTest;
 import org.apache.maven.plugin.surefire.util.DirectoryScannerTest;
-import org.apache.maven.plugin.surefire.util.ImmutableMapTest;
 import org.apache.maven.plugin.surefire.util.SpecificFileFilterTest;
 import org.apache.maven.surefire.report.ConsoleOutputFileReporterTest;
 import org.apache.maven.surefire.report.FileReporterTest;
@@ -73,8 +72,7 @@ import org.junit.runners.Suite;
     TestLessInputStreamBuilderTest.class,
     SPITest.class,
     SurefireReflectorTest.class,
-    ImmutableMapTest.class,
-    SurefireHelperTest.class,
+    SurefireHelperTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index f0f0ac6..b8a006b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -19,9 +19,6 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
-import java.io.PrintStream;
-import java.util.Properties;
-
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
@@ -31,9 +28,15 @@ import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SafeThrowable;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
+
+import java.io.PrintStream;
+import java.util.Map.Entry;
 
 import static java.lang.Integer.toHexString;
 import static java.nio.charset.Charset.defaultCharset;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.useNonNull;
 import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
 import static org.apache.maven.surefire.util.internal.StringUtils.escapeBytesToPrintable;
 import static org.apache.maven.surefire.util.internal.StringUtils.escapeToPrintable;
@@ -132,13 +135,13 @@ public class ForkingRunListener
     }
 
     @Override
-    public void testSetStarting( ReportEntry report )
+    public void testSetStarting( TestSetReportEntry report )
     {
         encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) );
     }
 
     @Override
-    public void testSetCompleted( ReportEntry report )
+    public void testSetCompleted( TestSetReportEntry report )
     {
         encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) );
     }
@@ -187,15 +190,10 @@ public class ForkingRunListener
 
     void sendProps()
     {
-        Properties systemProperties = System.getProperties();
-
-        if ( systemProperties != null )
+        for ( Entry<String, String> entry : systemProps().entrySet() )
         {
-            for ( final String key : systemProperties.stringPropertyNames() )
-            {
-                String value = systemProperties.getProperty( key );
-                encodeAndWriteToTarget( toPropertyString( key, value == null ? "null" : value ) );
-            }
+            String value = entry.getValue();
+            encodeAndWriteToTarget( toPropertyString( entry.getKey(), useNonNull( value, "null" ) ) );
         }
     }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
index c357cba..47b0c48 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
@@ -19,6 +19,9 @@ package org.apache.maven.surefire.report;
  * under the License.
  */
 
+import java.util.Collections;
+import java.util.Map;
+
 /**
  * @author Kristian Rosenvold
  */
@@ -47,16 +50,23 @@ public class CategorizedReportEntry
     public CategorizedReportEntry( String source, String name, String group, StackTraceWriter stackTraceWriter,
                                    Integer elapsed, String message )
     {
-        super( source, name, stackTraceWriter, elapsed, message );
+        this( source, name, group, stackTraceWriter, elapsed, message, Collections.<String, String>emptyMap() );
+    }
+
+    public CategorizedReportEntry( String source, String name, String group, StackTraceWriter stackTraceWriter,
+                                   Integer elapsed, String message, Map<String, String> systemProperties )
+    {
+        super( source, name, stackTraceWriter, elapsed, message, systemProperties );
         this.group = group;
     }
 
-    public static ReportEntry reportEntry( String source, String name, String group, StackTraceWriter stackTraceWriter,
-                                           Integer elapsed, String message )
+    public static TestSetReportEntry reportEntry( String source, String name, String group,
+                                                  StackTraceWriter stackTraceWriter, Integer elapsed, String message,
+                                                  Map<String, String> systemProperties )
     {
         return group != null
-            ? new CategorizedReportEntry( source, name, group, stackTraceWriter, elapsed, message )
-            : new SimpleReportEntry( source, name, stackTraceWriter, elapsed, message );
+            ? new CategorizedReportEntry( source, name, group, stackTraceWriter, elapsed, message, systemProperties )
+            : new SimpleReportEntry( source, name, stackTraceWriter, elapsed, message, systemProperties );
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
index b964430..b80966d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
@@ -34,7 +34,7 @@ public interface RunListener
      * @param report the report entry describing the testset
      * @throws ReporterException When reporting fails
      */
-    void testSetStarting( ReportEntry report );
+    void testSetStarting( TestSetReportEntry report );
 
     /**
      * Indicates end of a given test-set
@@ -42,7 +42,7 @@ public interface RunListener
      * @param report the report entry describing the testset
      * @throws ReporterException When reporting fails
      */
-    void testSetCompleted( ReportEntry report );
+    void testSetCompleted( TestSetReportEntry report );
 
     /**
      * Event fired when a test is about to start

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
index 28a19f9..c2bc48f 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
@@ -19,12 +19,19 @@ package org.apache.maven.surefire.report;
  * under the License.
  */
 
+import org.apache.maven.surefire.util.internal.ImmutableMap;
+
+import java.util.Collections;
+import java.util.Map;
+
 /**
  * @author Kristian Rosenvold
  */
 public class SimpleReportEntry
-    implements ReportEntry
+    implements TestSetReportEntry
 {
+    private Map<String, String> systemProperties;
+
     private final String source;
 
     private final String name;
@@ -45,6 +52,11 @@ public class SimpleReportEntry
         this( source, name, null, null );
     }
 
+    public SimpleReportEntry( String source, String name, Map<String, String> systemProperties )
+    {
+        this( source, name, null, null, systemProperties );
+    }
+
     private SimpleReportEntry( String source, String name, StackTraceWriter stackTraceWriter )
     {
         this( source, name, stackTraceWriter, null );
@@ -57,11 +69,11 @@ public class SimpleReportEntry
 
     public SimpleReportEntry( String source, String name, String message )
     {
-        this( source, name, null, null, message );
+        this( source, name, null, null, message, Collections.<String, String>emptyMap() );
     }
 
     protected SimpleReportEntry( String source, String name, StackTraceWriter stackTraceWriter, Integer elapsed,
-                                 String message )
+                                 String message, Map<String, String> systemProperties )
     {
         if ( source == null )
         {
@@ -81,13 +93,19 @@ public class SimpleReportEntry
         this.message = message;
 
         this.elapsed = elapsed;
-    }
 
+        this.systemProperties = new ImmutableMap<String, String>( systemProperties );
+    }
 
     public SimpleReportEntry( String source, String name, StackTraceWriter stackTraceWriter, Integer elapsed )
     {
-        //noinspection ThrowableResultOfMethodCallIgnored
-        this( source, name, stackTraceWriter, elapsed, safeGetMessage( stackTraceWriter ) );
+        this( source, name, stackTraceWriter, elapsed, Collections.<String, String>emptyMap() );
+    }
+
+    public SimpleReportEntry( String source, String name, StackTraceWriter stackTraceWriter, Integer elapsed,
+                              Map<String, String> systemProperties )
+    {
+        this( source, name, stackTraceWriter, elapsed, safeGetMessage( stackTraceWriter ), systemProperties );
     }
 
     public static SimpleReportEntry assumption( String source, String name, String message )
@@ -215,4 +233,10 @@ public class SimpleReportEntry
     {
         return getName();
     }
+
+    @Override
+    public Map<String, String> getSystemProperties()
+    {
+        return systemProperties;
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/report/TestSetReportEntry.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/TestSetReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/TestSetReportEntry.java
new file mode 100644
index 0000000..02d8669
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/TestSetReportEntry.java
@@ -0,0 +1,35 @@
+package org.apache.maven.surefire.report;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Map;
+
+/**
+ * Describes test-set when started and finished.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @see RunListener#testSetStarting(TestSetReportEntry)
+ * @see RunListener#testSetCompleted(TestSetReportEntry)
+ * @since 2.20.1
+ */
+public interface TestSetReportEntry extends ReportEntry
+{
+    Map<String, String> getSystemProperties();
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ImmutableMap.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ImmutableMap.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ImmutableMap.java
new file mode 100644
index 0000000..003d884
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ImmutableMap.java
@@ -0,0 +1,134 @@
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.AbstractMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static java.util.Collections.unmodifiableSet;
+
+/**
+ * Copies input map in {@link #ImmutableMap(Map) constructor}, and Entries are linked and thread-safe.
+ * The map is immutable with linear list of entries.
+ *
+ * @param <K> key
+ * @param <V> value
+ * @since 2.20
+ */
+public final class ImmutableMap<K, V>
+        extends AbstractMap<K, V>
+{
+    private final Node<K, V> first;
+
+    public ImmutableMap( Map<K, V> map )
+    {
+        Node<K, V> first = null;
+        Node<K, V> previous = null;
+        for ( Entry<K, V> e : map.entrySet() )
+        {
+            Node<K, V> node = new Node<K, V>( e.getKey(), e.getValue() );
+            if ( first == null )
+            {
+                first = node;
+            }
+            else
+            {
+                previous.next = node;
+            }
+            previous = node;
+        }
+        this.first = first;
+    }
+
+    @Override
+    public Set<Entry<K, V>> entrySet()
+    {
+        Set<Entry<K, V>> entries = new LinkedHashSet<Entry<K, V>>();
+        Node<K, V> node = first;
+        while ( node != null )
+        {
+            entries.add( node );
+            node = node.next;
+        }
+        return unmodifiableSet( entries );
+    }
+
+    static final class Node<K, V>
+            implements Entry<K, V>
+    {
+        final K key;
+        final V value;
+        volatile Node<K, V> next;
+
+        Node( K key, V value )
+        {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Override
+        public K getKey()
+        {
+            return key;
+        }
+
+        @Override
+        public V getValue()
+        {
+            return value;
+        }
+
+        @Override
+        public V setValue( V value )
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean equals( Object o )
+        {
+            if ( this == o )
+            {
+                return true;
+            }
+
+            if ( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+
+            Node<?, ?> node = (Node<?, ?>) o;
+
+            return getKey() != null ? getKey().equals( node.getKey() ) : node.getKey() == null
+                           && getValue() != null ? getValue().equals( node.getValue() ) : node.getValue() == null;
+
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int result = getKey() != null ? getKey().hashCode() : 0;
+            result = 31 * result + ( getValue() != null ? getValue().hashCode() : 0 );
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ObjectUtils.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ObjectUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ObjectUtils.java
index 996c3be..ae98935 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ObjectUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ObjectUtils.java
@@ -1 +1 @@
-package org.apache.maven.surefire.util.internal;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * Similar to Java 7 java.util.Objects.
 *
 * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
 * @since 2
 .20
 */
public final class ObjectUtils
{
    private ObjectUtils()
    {
        throw new IllegalStateException( "no instantiable constructor" );
    }

    public static <T> T useNonNull( T target, T fallback )
    {
        return isNull( target ) ? fallback : target;
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static boolean isNull( Object target )
    {
        return target == null;
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static boolean nonNull( Object target )
    {
        return !isNull( target );
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static <T> T requireNonNull( T obj, String message )
    {
        if ( isNull( obj ) )
        {
            throw new NullPointerException( message );
        }
        return obj;
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static <T> T requireNonNul
 l( T obj )
    {
        return requireNonNull( obj, null );
    }
}
\ No newline at end of file
+package org.apache.maven.surefire.util.internal;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.lang.management.ManagementFactory;
import java.util.Map;

/**
 * Similar to Java 7 java.util.Objects.
 *
 * @author <a href=
 "mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
 * @since 2.20
 */
public final class ObjectUtils
{
    private ObjectUtils()
    {
        throw new IllegalStateException( "no instantiable constructor" );
    }

    public static <T> T useNonNull( T target, T fallback )
    {
        return isNull( target ) ? fallback : target;
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static boolean isNull( Object target )
    {
        return target == null;
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static boolean nonNull( Object target )
    {
        return !isNull( target );
    }

    /*
    * In JDK7 use java.util.Objects instead.
    * todo
    * */
    public static <T> T requireNonNull( T obj, String message )
    {
        if ( isNull( obj ) )
        {
            throw new NullPointerException( message );
        }
        return obj;
    }

    /*
    * In JDK7 use java.util.Obje
 cts instead.
    * todo
    * */
    public static <T> T requireNonNull( T obj )
    {
        return requireNonNull( obj, null );
    }

    public static Map<String, String> systemProps()
    {
        return ManagementFactory.getRuntimeMXBean().getSystemProperties();
    }
}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index c43a3a6..f370880 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -39,6 +39,7 @@ import org.apache.maven.surefire.util.TestsToRunTest;
 import org.apache.maven.surefire.util.UrlUtilsTest;
 import org.apache.maven.surefire.util.internal.ByteBufferTest;
 import org.apache.maven.surefire.util.internal.ConcurrencyUtilsTest;
+import org.apache.maven.surefire.util.internal.ImmutableMapTest;
 import org.apache.maven.surefire.util.internal.StringUtilsTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -68,7 +69,8 @@ import org.junit.runners.Suite;
     TestsToRunTest.class,
     UrlUtilsTest.class,
     SpecificTestClassFilterTest.class,
-    FundamentalFilterTest.class
+    FundamentalFilterTest.class,
+    ImmutableMapTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ImmutableMapTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ImmutableMapTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ImmutableMapTest.java
new file mode 100644
index 0000000..b104cc3
--- /dev/null
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ImmutableMapTest.java
@@ -0,0 +1,86 @@
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.surefire.util.internal.ImmutableMap.Node;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @since 2.20
+ */
+public class ImmutableMapTest
+{
+    private ImmutableMap<String, String> map;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        Map<String, String> backingMap = new HashMap<String, String>();
+        backingMap.put( "a", "1" );
+        backingMap.put( "x", null );
+        backingMap.put( "b", "2" );
+        backingMap.put( "c", "3" );
+        backingMap.put( "", "" );
+        backingMap.put( null, "1" );
+        map = new ImmutableMap<String, String>( backingMap );
+    }
+
+    @Test
+    public void testEntrySet() throws Exception
+    {
+        Set<Entry<String, String>> entries = map.entrySet();
+        assertThat( entries, hasSize( 6 ) );
+        assertThat( entries, hasItem( new Node<String, String>( "a", "1" ) ) );
+        assertThat( entries, hasItem( new Node<String, String>( "x", null ) ) );
+        assertThat( entries, hasItem( new Node<String, String>( "b", "2" ) ) );
+        assertThat( entries, hasItem( new Node<String, String>( "c", "3" ) ) );
+        assertThat( entries, hasItem( new Node<String, String>( "", "" ) ) );
+        assertThat( entries, hasItem( new Node<String, String>( null, "1" ) ) );
+    }
+
+    @Test
+    public void testGetter()
+    {
+        assertThat( map.size(), is( 6 ) );
+        assertThat( map.get( "a" ), is( "1" ) );
+        assertThat( map.get( "x" ), is( (String) null ) );
+        assertThat( map.get( "b" ), is( "2" ) );
+        assertThat( map.get( "c" ), is( "3" ) );
+        assertThat( map.get( "" ), is( "" ) );
+        assertThat( map.get( null ), is( "1" ) );
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldNotModifyEntries()
+    {
+        map.entrySet().clear();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
----------------------------------------------------------------------
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
index 12cbb4c..9f3b6ff 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/junit4/MockReporter.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 
 /**
  * Internal tests use only.
@@ -56,13 +57,13 @@ public class MockReporter
     }
 
     @Override
-    public void testSetStarting( ReportEntry report )
+    public void testSetStarting( TestSetReportEntry report )
     {
         events.add( SET_STARTED );
     }
 
     @Override
-    public void testSetCompleted( ReportEntry report )
+    public void testSetCompleted( TestSetReportEntry report )
     {
         events.add( SET_COMPLETED );
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
index adfda35..b8c83e1 100644
--- a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
+++ b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
@@ -25,7 +25,6 @@ import org.apache.maven.surefire.providerapi.AbstractProvider;
 import org.apache.maven.surefire.providerapi.ProviderParameters;
 import org.apache.maven.surefire.report.ConsoleOutputCapture;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
-import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterFactory;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
@@ -36,6 +35,10 @@ import org.apache.maven.surefire.util.RunOrderCalculator;
 import org.apache.maven.surefire.util.ScanResult;
 import org.apache.maven.surefire.util.TestsToRun;
 
+import java.util.Map;
+
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
+
 /**
  * @author Kristian Rosenvold
  */
@@ -95,8 +98,8 @@ public class JUnit3Provider
         {
             final RunListener reporter = reporterFactory.createReporter();
             ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
-
-            final String smClassName = System.getProperty( "surefire.security.manager" );
+            final Map<String, String> systemProperties = systemProps();
+            final String smClassName = systemProperties.get( "surefire.security.manager" );
             if ( smClassName != null )
             {
                 SecurityManager securityManager =
@@ -107,7 +110,7 @@ public class JUnit3Provider
             for ( Class<?> clazz : testsToRun )
             {
                 SurefireTestSet surefireTestSet = createTestSet( clazz );
-                executeTestSet( surefireTestSet, reporter, testClassLoader );
+                executeTestSet( surefireTestSet, reporter, testClassLoader, systemProperties );
             }
 
         }
@@ -126,10 +129,11 @@ public class JUnit3Provider
             : new PojoTestSet( clazz );
     }
 
-    private void executeTestSet( SurefireTestSet testSet, RunListener reporter, ClassLoader classLoader )
+    private void executeTestSet( SurefireTestSet testSet, RunListener reporter, ClassLoader classLoader,
+                                 Map<String, String> systemProperties )
         throws TestSetFailedException
     {
-        ReportEntry report = new SimpleReportEntry( this.getClass().getName(), testSet.getName() );
+        SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), testSet.getName(), systemProperties );
 
         reporter.testSetStarting( report );
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
index 359a79f..9c08fd9 100644
--- a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
+++ b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
@@ -19,16 +19,17 @@ package org.apache.maven.surefire.junit;
  * under the License.
  */
 
-import java.util.ArrayList;
-import java.util.List;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 import org.apache.maven.surefire.common.junit3.JUnit3Reflector;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import java.util.ArrayList;
+import java.util.List;
 
 public class JUnitTestSetTest
     extends TestCase
@@ -64,12 +65,12 @@ public class JUnitTestSetTest
         private List<ReportEntry> succeededTests = new ArrayList<ReportEntry>();
 
         @Override
-        public void testSetStarting( ReportEntry report )
+        public void testSetStarting( TestSetReportEntry report )
         {
         }
 
         @Override
-        public void testSetCompleted( ReportEntry report )
+        public void testSetCompleted( TestSetReportEntry report )
         {
         }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
----------------------------------------------------------------------
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 12842fa..ad29224 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
@@ -31,7 +31,6 @@ import org.apache.maven.surefire.providerapi.AbstractProvider;
 import org.apache.maven.surefire.providerapi.ProviderParameters;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.PojoStackTraceWriter;
-import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterFactory;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
@@ -66,6 +65,7 @@ import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture
 import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
 import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
 import static org.apache.maven.surefire.util.TestsToRun.fromClass;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
 import static org.junit.runner.Request.aClass;
 import static org.junit.runner.Request.method;
 
@@ -232,7 +232,7 @@ public class JUnit4Provider
 
     private void executeTestSet( Class<?> clazz, RunListener reporter, Notifier notifier )
     {
-        final ReportEntry report = new SimpleReportEntry( getClass().getName(), clazz.getName() );
+        final SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), clazz.getName(), systemProps() );
         reporter.testSetStarting( report );
         try
         {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
index 8095dbf..6af12dc 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ConcurrentRunListener.java
@@ -26,6 +26,7 @@ import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterFactory;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 
 import static org.apache.maven.surefire.junitcore.TestMethod.getThreadTestMethod;
@@ -70,12 +71,12 @@ public abstract class ConcurrentRunListener
     }
 
     @Override
-    public void testSetStarting( ReportEntry description )
+    public void testSetStarting( TestSetReportEntry description )
     {
     }
 
     @Override
-    public void testSetCompleted( ReportEntry result )
+    public void testSetCompleted( TestSetReportEntry result )
     {
         final RunListener reporterManager = getRunListener();
         for ( TestSet testSet : classMethodCounts.values() )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
index 0e5ee77..8db29d3 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
@@ -23,11 +23,14 @@ import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.junit.runner.Description;
 import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
 
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
+
 /**
  * A class to be used when there is no JUnit parallelism (methods or/and class). This allow to workaround JUnit
  * limitation a la Junit4 provider. Specifically, we can redirect properly the output even if we don't have class
@@ -60,10 +63,10 @@ public class NonConcurrentRunListener
         return new SimpleReportEntry( extractDescriptionClassName( description ), description.getDisplayName() );
     }
 
-    protected SimpleReportEntry createReportEntryForTestSet( Description description )
+    private TestSetReportEntry createReportEntryForTestSet( Description description )
     {
         String testClassName = extractDescriptionClassName( description );
-        return new SimpleReportEntry( testClassName, testClassName );
+        return new SimpleReportEntry( testClassName, testClassName, systemProps() );
     }
 
     @Override
@@ -93,7 +96,8 @@ public class NonConcurrentRunListener
             currentTestSetDescription = description;
             if ( lastFinishedDescription != null )
             {
-                reporter.testSetCompleted( createReportEntryForTestSet( lastFinishedDescription ) );
+                TestSetReportEntry reportEntry = createReportEntryForTestSet( lastFinishedDescription );
+                reporter.testSetCompleted( reportEntry );
                 lastFinishedDescription = null;
             }
             reporter.testSetStarting( createReportEntryForTestSet( description ) );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestSet.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestSet.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestSet.java
index d7bb722..37ca8b0 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestSet.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/TestSet.java
@@ -29,6 +29,7 @@ import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 
+import org.apache.maven.surefire.report.TestSetReportEntry;
 import org.junit.runner.Description;
 
 /**
@@ -64,7 +65,7 @@ public class TestSet
         {
             try
             {
-                ReportEntry report = createReportEntry( null );
+                TestSetReportEntry report = createReportEntry( null );
 
                 target.testSetStarting( report );
 
@@ -106,7 +107,7 @@ public class TestSet
         return testMethod;
     }
 
-    private ReportEntry createReportEntry( Integer elapsed )
+    private TestSetReportEntry createReportEntry( Integer elapsed )
     {
         final String className = testSetDescription.getClassName();
         final boolean isJunit3 = className == null;

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/d303e625/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
index a74ef0d..ca40f7c 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
@@ -19,13 +19,15 @@ package org.apache.maven.surefire.testng;
  * under the License.
  */
 
-import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterException;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 
 import java.util.Map;
 
+import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
+
 /**
  * Abstract class which implements common functions.
  */
@@ -41,7 +43,7 @@ abstract class TestSuite
 
     final void startTestSuite( RunListener reporterManager )
     {
-        ReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName() );
+        TestSetReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName(), systemProps() );
 
         try
         {
@@ -55,7 +57,7 @@ abstract class TestSuite
 
     final void finishTestSuite( RunListener reporterManager )
     {
-        ReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName() );
+        SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName(), systemProps() );
         reporterManager.testSetCompleted( report );
     }
 }