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 2018/09/06 23:35:29 UTC

[maven-surefire] branch INV1561 updated (b28c3ad -> 232d260)

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

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


    from b28c3ad  parallel test suites in Surefire1535TestNGParallelSuitesIT corrupted TEST-*.xml
     new b7e8c38  1177
     new 232d260  [SUREFIRE-1565] Surefire should support parameterized reportsDirectory

The 2 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:
 .../plugin/surefire/AbstractSurefireMojo.java      |  20 +---
 .../surefire/StartupReportConfiguration.java       |  28 ++---
 .../maven/plugin/surefire/SurefireHelper.java      |  49 +++++++++
 .../surefire/booterclient/BooterSerializer.java    |   6 +-
 .../booterclient/DefaultForkConfiguration.java     |  16 +--
 .../plugin/surefire/booterclient/ForkStarter.java  |  64 ++++++-----
 .../surefire/booterclient/output/ForkClient.java   |  18 ++--
 .../output/InPluginProcessDumpSingleton.java       |  57 ++++++----
 .../output/NativeStdErrStreamConsumer.java         |   3 +-
 .../surefire/report/ConsoleOutputFileReporter.java |  38 ++++---
 .../surefire/report/DefaultReporterFactory.java    |  26 ++---
 .../surefire/report/NullConsoleOutputReceiver.java |  59 ----------
 .../maven/plugin/surefire/SurefireHelperTest.java  |  26 ++++-
 ...ooterDeserializerProviderConfigurationTest.java |   2 +-
 ...BooterDeserializerStartupConfigurationTest.java |   4 +-
 .../booterclient/ForkingRunListenerTest.java       |  10 +-
 .../report/ConsoleOutputFileReporterTest.java      |   8 +-
 maven-surefire-plugin/src/site/fml/faq.fml         |   1 +
 .../maven/surefire/booter/DumpErrorSingleton.java  |  15 ++-
 .../surefire/util/internal/DumpFileUtils.java      |   8 +-
 .../apache/maven/surefire/booter/ForkedBooter.java |   3 +-
 .../maven/surefire/its/fixture/TestFile.java       |  11 +-
 .../jiras/Surefire1177TestngParallelSuitesIT.java  |  24 ++++-
 .../jiras/Surefire1535TestNGParallelSuitesIT.java  | 119 +++++++++++++++++++--
 .../surefire-1535-parallel-testng/pom.xml          |  48 ++++-----
 .../src/test/java/it/ParallelTest1.java            |   1 +
 .../src/test/java/it/ParallelTest2.java            |   1 +
 .../test/resources/testng-parallel-suites/pom.xml  |   1 -
 28 files changed, 404 insertions(+), 262 deletions(-)
 delete mode 100644 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java


[maven-surefire] 01/02: 1177

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

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

commit b7e8c386f88f6c6245a98d24c6f8b258cec3ef3c
Author: Tibor17 <ti...@apache.org>
AuthorDate: Fri Sep 7 01:13:59 2018 +0200

    1177
---
 .../jiras/Surefire1177TestngParallelSuitesIT.java  | 24 ++++++++++++++++++++--
 .../test/resources/testng-parallel-suites/pom.xml  |  1 -
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1177TestngParallelSuitesIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1177TestngParallelSuitesIT.java
index 80d3a78..28cc78c 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1177TestngParallelSuitesIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1177TestngParallelSuitesIT.java
@@ -43,12 +43,32 @@ public class Surefire1177TestngParallelSuitesIT
     private static final String UNEXPECTED_LINE = "ShouldNotRunTest#shouldNotRun()";
 
     @Test
-    public void shouldRunTwoSuitesInParallel()
+    public void twoSuitesInParallel()
         throws VerificationException
     {
         assumeJavaVersion( 1.7d );
 
-        OutputValidator validator = unpack().executeTest().verifyErrorFree( 2 );
+        OutputValidator validator = unpack()
+                .forkMode( "never" )
+                .executeTest()
+                .verifyErrorFree( 2 );
+
+        validator.assertThatLogLine( startsWith( EXPECTED_LINE ), is( 2 ) );
+        validator.assertThatLogLine( is( EXPECTED_LINE + " 1." ), is( 1 ) );
+        validator.assertThatLogLine( is( EXPECTED_LINE + " 2." ), is( 1 ) );
+        validator.assertThatLogLine( containsString( UNEXPECTED_LINE ), is( 0 ) );
+    }
+
+    @Test
+    public void twoSuitesInParallelForked()
+            throws VerificationException
+    {
+        assumeJavaVersion( 1.7d );
+
+        OutputValidator validator = unpack()
+                .forkMode( "once" )
+                .executeTest()
+                .verifyErrorFree( 2 );
 
         validator.assertThatLogLine( startsWith( EXPECTED_LINE ), is( 2 ) );
         validator.assertThatLogLine( is( EXPECTED_LINE + " 1." ), is( 1 ) );
diff --git a/surefire-its/src/test/resources/testng-parallel-suites/pom.xml b/surefire-its/src/test/resources/testng-parallel-suites/pom.xml
index d0989fb..e3e347b 100644
--- a/surefire-its/src/test/resources/testng-parallel-suites/pom.xml
+++ b/surefire-its/src/test/resources/testng-parallel-suites/pom.xml
@@ -63,7 +63,6 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <!--<forkMode>once</forkMode>-->
           <suiteXmlFiles>
             <file>src/test/resources/testng1.xml</file>
             <file>src/test/resources/testng2.xml</file>


[maven-surefire] 02/02: [SUREFIRE-1565] Surefire should support parameterized reportsDirectory

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

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

commit 232d260cad3091f3315f880a061efdf7c03d9c65
Author: Tibor17 <ti...@apache.org>
AuthorDate: Fri Sep 7 01:35:21 2018 +0200

    [SUREFIRE-1565] Surefire should support parameterized reportsDirectory
---
 .../plugin/surefire/AbstractSurefireMojo.java      |  20 +---
 .../surefire/StartupReportConfiguration.java       |  28 ++---
 .../maven/plugin/surefire/SurefireHelper.java      |  49 +++++++++
 .../surefire/booterclient/BooterSerializer.java    |   6 +-
 .../booterclient/DefaultForkConfiguration.java     |  16 +--
 .../plugin/surefire/booterclient/ForkStarter.java  |  64 ++++++-----
 .../surefire/booterclient/output/ForkClient.java   |  18 ++--
 .../output/InPluginProcessDumpSingleton.java       |  57 ++++++----
 .../output/NativeStdErrStreamConsumer.java         |   3 +-
 .../surefire/report/ConsoleOutputFileReporter.java |  38 ++++---
 .../surefire/report/DefaultReporterFactory.java    |  26 ++---
 .../surefire/report/NullConsoleOutputReceiver.java |  59 ----------
 .../maven/plugin/surefire/SurefireHelperTest.java  |  26 ++++-
 ...ooterDeserializerProviderConfigurationTest.java |   2 +-
 ...BooterDeserializerStartupConfigurationTest.java |   4 +-
 .../booterclient/ForkingRunListenerTest.java       |  10 +-
 .../report/ConsoleOutputFileReporterTest.java      |   8 +-
 maven-surefire-plugin/src/site/fml/faq.fml         |   1 +
 .../maven/surefire/booter/DumpErrorSingleton.java  |  15 ++-
 .../surefire/util/internal/DumpFileUtils.java      |   8 +-
 .../apache/maven/surefire/booter/ForkedBooter.java |   3 +-
 .../maven/surefire/its/fixture/TestFile.java       |  11 +-
 .../jiras/Surefire1535TestNGParallelSuitesIT.java  | 119 +++++++++++++++++++--
 .../surefire-1535-parallel-testng/pom.xml          |  48 ++++-----
 .../src/test/java/it/ParallelTest1.java            |   1 +
 .../src/test/java/it/ParallelTest2.java            |   1 +
 26 files changed, 382 insertions(+), 259 deletions(-)

diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index fa19214..cc3dff9 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -120,6 +120,7 @@ import static java.util.Collections.singletonMap;
 import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.maven.plugin.surefire.util.DependencyScanner.filter;
+import static org.apache.maven.plugin.surefire.SurefireHelper.replaceThreadNumberPlaceholders;
 import static org.apache.maven.shared.utils.StringUtils.capitalizeFirstLetter;
 import static org.apache.maven.shared.utils.StringUtils.isEmpty;
 import static org.apache.maven.shared.utils.StringUtils.isNotBlank;
@@ -769,19 +770,6 @@ public abstract class AbstractSurefireMojo
 
     private int effectiveForkCount = -1;
 
-    /**
-     * The placeholder that is replaced by the executing thread's running number. The thread number
-     * range starts with 1
-     * Deprecated.
-     */
-    public static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}";
-
-    /**
-     * The placeholder that is replaced by the executing fork's running number. The fork number
-     * range starts with 1
-     */
-    public static final String FORK_NUMBER_PLACEHOLDER = "${surefire.forkNumber}";
-
     protected abstract String getPluginName();
 
     protected abstract int getRerunFailingTestsCount();
@@ -1215,16 +1203,12 @@ public abstract class AbstractSurefireMojo
         SurefireProperties effectiveSystemProperties, int threadNumber )
     {
         SurefireProperties filteredProperties = new SurefireProperties( ( KeyValueSource) effectiveSystemProperties );
-        String threadNumberString = String.valueOf( threadNumber );
         for ( Entry<Object, Object> entry : effectiveSystemProperties.entrySet() )
         {
             if ( entry.getValue() instanceof String )
             {
                 String value = (String) entry.getValue();
-                value = value.replace( THREAD_NUMBER_PLACEHOLDER, threadNumberString );
-                value = value.replace( FORK_NUMBER_PLACEHOLDER, threadNumberString );
-
-                filteredProperties.put( entry.getKey(), value );
+                filteredProperties.put( entry.getKey(), replaceThreadNumberPlaceholders( value, threadNumber ) );
             }
         }
         return filteredProperties;
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 caf0db3..26d4d18 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
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import static org.apache.maven.plugin.surefire.SurefireHelper.replaceForkThreadsInPath;
 import static org.apache.maven.plugin.surefire.report.ConsoleReporter.BRIEF;
 import static org.apache.maven.plugin.surefire.report.ConsoleReporter.PLAIN;
 import static org.apache.commons.lang3.StringUtils.trimToNull;
@@ -47,10 +48,6 @@ import static org.apache.commons.lang3.StringUtils.trimToNull;
  */
 public final class StartupReportConfiguration
 {
-    public static final String BRIEF_REPORT_FORMAT = BRIEF;
-
-    public static final String PLAIN_REPORT_FORMAT = PLAIN;
-
     private final PrintStream originalSystemOut;
 
     private final PrintStream originalSystemErr;
@@ -151,31 +148,31 @@ public final class StartupReportConfiguration
         return rerunFailingTestsCount;
     }
 
-    public StatelessXmlReporter instantiateStatelessXmlReporter()
+    public StatelessXmlReporter instantiateStatelessXmlReporter( Integer forkNumber )
     {
         return isDisableXmlReport()
             ? null
-            : new StatelessXmlReporter( reportsDirectory, reportNameSuffix, trimStackTrace, rerunFailingTestsCount,
-                                        testClassMethodRunHistory, xsdSchemaLocation );
+            : new StatelessXmlReporter( resolveReportsDirectory( forkNumber ), reportNameSuffix, trimStackTrace,
+                rerunFailingTestsCount, testClassMethodRunHistory, xsdSchemaLocation );
     }
 
-    public FileReporter instantiateFileReporter()
+    public FileReporter instantiateFileReporter( Integer forkNumber )
     {
         return isUseFile() && isBriefOrPlainFormat()
-            ? new FileReporter( reportsDirectory, getReportNameSuffix(), encoding )
+            ? new FileReporter( resolveReportsDirectory( forkNumber ), reportNameSuffix, encoding )
             : null;
     }
 
     public boolean isBriefOrPlainFormat()
     {
         String fmt = getReportFormat();
-        return BRIEF_REPORT_FORMAT.equals( fmt ) || PLAIN_REPORT_FORMAT.equals( fmt );
+        return BRIEF.equals( fmt ) || PLAIN.equals( fmt );
     }
 
-    public TestcycleConsoleOutputReceiver instantiateConsoleOutputFileReporter()
+    public TestcycleConsoleOutputReceiver instantiateConsoleOutputFileReporter( Integer forkNumber )
     {
         return isRedirectTestOutputToFile()
-            ? new ConsoleOutputFileReporter( reportsDirectory, getReportNameSuffix() )
+            ? new ConsoleOutputFileReporter( resolveReportsDirectory( forkNumber ), reportNameSuffix, forkNumber )
             : new DirectConsoleOutput( originalSystemOut, originalSystemErr );
     }
 
@@ -183,7 +180,7 @@ public final class StartupReportConfiguration
     {
         if ( statisticsReporter == null )
         {
-            statisticsReporter = requiresRunHistory ? new StatisticsReporter( getStatisticsFile() ) : null;
+            statisticsReporter = requiresRunHistory ? new StatisticsReporter( statisticsFile ) : null;
         }
         return statisticsReporter;
     }
@@ -217,4 +214,9 @@ public final class StartupReportConfiguration
     {
         return encoding;
     }
+
+    private File resolveReportsDirectory( Integer forkNumber )
+    {
+        return forkNumber == null ? reportsDirectory : replaceForkThreadsInPath( reportsDirectory, forkNumber );
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
index dd29cb4..44dbdd4 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
@@ -29,10 +29,14 @@ import org.apache.maven.surefire.suite.RunResult;
 import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.apache.maven.surefire.util.internal.DumpFileUtils;
 
+import javax.annotation.Nonnull;
+import java.io.File;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Deque;
+import java.util.LinkedList;
 import java.util.List;
 
 import static java.util.Collections.unmodifiableList;
@@ -54,8 +58,14 @@ public final class SurefireHelper
 
     public static final String DUMP_FILE_PREFIX = DUMP_FILE_DATE + "-jvmRun";
 
+    public static final String DUMP_FILENAME_FORMATTER = DUMP_FILE_PREFIX + "%d" + DUMP_FILE_EXT;
+
     public static final String DUMPSTREAM_FILENAME_FORMATTER = DUMP_FILE_PREFIX + "%d" + DUMPSTREAM_FILE_EXT;
 
+    public static final String DUMPSTREAM_FILENAME = DUMP_FILE_DATE + DUMPSTREAM_FILE_EXT;
+
+    public static final String DUMP_FILENAME = DUMP_FILE_DATE + DUMP_FILE_EXT;
+
     /**
      * The maximum path that does not require long path prefix on Windows.<br>
      * See {@code sun/nio/fs/WindowsPath} in
@@ -71,12 +81,26 @@ public final class SurefireHelper
 
     private static final String[] DUMP_FILES_PRINT =
             {
+                    "[date]" + DUMP_FILE_EXT,
                     "[date]-jvmRun[N]" + DUMP_FILE_EXT,
                     "[date]" + DUMPSTREAM_FILE_EXT,
                     "[date]-jvmRun[N]" + DUMPSTREAM_FILE_EXT
             };
 
     /**
+     * The placeholder that is replaced by the executing thread's running number. The thread number
+     * range starts with 1
+     * Deprecated.
+     */
+    private static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}";
+
+    /**
+     * The placeholder that is replaced by the executing fork's running number. The fork number
+     * range starts with 1
+     */
+    private static final String FORK_NUMBER_PLACEHOLDER = "${surefire.forkNumber}";
+
+    /**
      * Do not instantiate.
      */
     private SurefireHelper()
@@ -84,6 +108,31 @@ public final class SurefireHelper
         throw new IllegalAccessError( "Utility class" );
     }
 
+    @Nonnull
+    public static String replaceThreadNumberPlaceholders( @Nonnull String argLine, int threadNumber )
+    {
+        String threadNumberAsString = String.valueOf( threadNumber );
+        return argLine.replace( THREAD_NUMBER_PLACEHOLDER, threadNumberAsString )
+                .replace( FORK_NUMBER_PLACEHOLDER, threadNumberAsString );
+    }
+
+    public static File replaceForkThreadsInPath( File path, int replacement )
+    {
+        Deque<String> dirs = new LinkedList<String>();
+        File root = path;
+        while ( !root.exists() )
+        {
+            dirs.addFirst( replaceThreadNumberPlaceholders( root.getName(), replacement ) );
+            root = root.getParentFile();
+        }
+        File replacedPath = root;
+        for ( String dir : dirs )
+        {
+            replacedPath = new File( replacedPath, dir );
+        }
+        return replacedPath;
+    }
+
     public static String[] getDumpFilesToPrint()
     {
         return DUMP_FILES_PRINT.clone();
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
index 9c501db..fe72fce 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
@@ -39,6 +39,7 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 
+import static org.apache.maven.plugin.surefire.SurefireHelper.replaceForkThreadsInPath;
 import static org.apache.maven.surefire.booter.AbstractPathConfiguration.CHILD_DELEGATION;
 import static org.apache.maven.surefire.booter.AbstractPathConfiguration.CLASSPATH;
 import static org.apache.maven.surefire.booter.AbstractPathConfiguration.ENABLE_ASSERTIONS;
@@ -99,7 +100,7 @@ class BooterSerializer
      */
     File serialize( KeyValueSource sourceProperties, ProviderConfiguration booterConfiguration,
                     StartupConfiguration providerConfiguration, Object testSet, boolean readTestsFromInStream,
-                    Long pid )
+                    Long pid, int forkNumber )
         throws IOException
     {
         SurefireProperties properties = new SurefireProperties( sourceProperties );
@@ -159,8 +160,9 @@ class BooterSerializer
 
         ReporterConfiguration reporterConfiguration = booterConfiguration.getReporterConfiguration();
         boolean rep = reporterConfiguration.isTrimStackTrace();
+        File reportsDirectory = replaceForkThreadsInPath( reporterConfiguration.getReportsDirectory(), forkNumber );
         properties.setProperty( ISTRIMSTACKTRACE, rep );
-        properties.setProperty( REPORTSDIRECTORY, reporterConfiguration.getReportsDirectory() );
+        properties.setProperty( REPORTSDIRECTORY, reportsDirectory );
         ClassLoaderConfiguration classLoaderConfig = providerConfiguration.getClassLoaderConfiguration();
         properties.setProperty( USESYSTEMCLASSLOADER, toString( classLoaderConfig.isUseSystemClassLoader() ) );
         properties.setProperty( USEMANIFESTONLYJAR, toString( classLoaderConfig.isUseManifestOnlyJar() ) );
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
index c35d01c..591491d 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfiguration.java
@@ -37,9 +37,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 
-import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.FORK_NUMBER_PLACEHOLDER;
-import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER;
+import static org.apache.maven.plugin.surefire.SurefireHelper.replaceForkThreadsInPath;
 import static org.apache.maven.plugin.surefire.util.Relocator.relocate;
+import static org.apache.maven.plugin.surefire.SurefireHelper.replaceThreadNumberPlaceholders;
 import static org.apache.maven.surefire.booter.Classpath.join;
 
 /**
@@ -169,7 +169,7 @@ public abstract class DefaultForkConfiguration
     private File getWorkingDirectory( int forkNumber )
             throws SurefireBooterForkException
     {
-        File cwd = new File( replaceThreadNumberPlaceholder( getWorkingDirectory().getAbsolutePath(), forkNumber ) );
+        File cwd = replaceForkThreadsInPath( getWorkingDirectory(), forkNumber );
 
         if ( !cwd.exists() && !cwd.mkdirs() )
         {
@@ -184,14 +184,6 @@ public abstract class DefaultForkConfiguration
         return cwd;
     }
 
-    @Nonnull
-    private static String replaceThreadNumberPlaceholder( @Nonnull String argLine, int threadNumber )
-    {
-        String threadNumberAsString = String.valueOf( threadNumber );
-        return argLine.replace( THREAD_NUMBER_PLACEHOLDER, threadNumberAsString )
-                .replace( FORK_NUMBER_PLACEHOLDER, threadNumberAsString );
-    }
-
     /**
      * Replaces expressions <pre>@{property-name}</pre> with the corresponding properties
      * from the model. This allows late evaluation of property values when the plugin is executed (as compared
@@ -331,7 +323,7 @@ public abstract class DefaultForkConfiguration
     private String newJvmArgLine( int forks )
     {
         String interpolatedArgs = stripNewLines( interpolateArgLineWithPropertyExpressions() );
-        String argsWithReplacedForkNumbers = replaceThreadNumberPlaceholder( interpolatedArgs, forks );
+        String argsWithReplacedForkNumbers = replaceThreadNumberPlaceholders( interpolatedArgs, forks );
         return extendJvmArgLine( argsWithReplacedForkNumbers );
     }
 
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 44b5bff..74645a4 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
@@ -197,8 +197,9 @@ public class ForkStarter
                     // if tests failed, but if this does not happen then printing warning to console is the only way to
                     // inform the users.
                     String msg = "ForkStarter IOException: " + e.getLocalizedMessage() + ".";
+                    File reportsDir = defaultReporterFactory.getReportsDirectory();
                     File dump = InPluginProcessDumpSingleton.getSingleton()
-                                        .dumpException( e, msg, defaultReporterFactory, jvmRun );
+                                        .dumpStreamException( e, msg, reportsDir, jvmRun );
                     log.warning( msg + " See the dump file " + dump.getAbsolutePath() );
                 }
             }
@@ -264,21 +265,25 @@ public class ForkStarter
     private RunResult run( SurefireProperties effectiveSystemProperties, Map<String, String> providerProperties )
             throws SurefireBooterForkException
     {
-        DefaultReporterFactory forkedReporterFactory = new DefaultReporterFactory( startupReportConfiguration, log );
-        defaultReporterFactories.add( forkedReporterFactory );
         TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
         PropertiesWrapper props = new PropertiesWrapper( providerProperties );
         TestLessInputStream stream = builder.build();
-        ForkClient forkClient = new ForkClient( forkedReporterFactory, stream, log, new AtomicBoolean() );
         Thread shutdown = createImmediateShutdownHookThread( builder, providerConfiguration.getShutdown() );
         ScheduledFuture<?> ping = triggerPingTimerForShutdown( builder );
+        int forkNumber = drawNumber();
         try
         {
             addShutDownHook( shutdown );
-            return fork( null, props, forkClient, effectiveSystemProperties, stream, false );
+            DefaultReporterFactory forkedReporterFactory =
+                    new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
+            defaultReporterFactories.add( forkedReporterFactory );
+            ForkClient forkClient =
+                    new ForkClient( forkedReporterFactory, stream, log, new AtomicBoolean(), forkNumber );
+            return fork( null, props, forkClient, effectiveSystemProperties, forkNumber, stream, false );
         }
         finally
         {
+            returnNumber( forkNumber );
             removeShutdownHook( shutdown );
             ping.cancel( true );
             builder.removeStream( stream );
@@ -344,10 +349,12 @@ public class ForkStarter
                     public RunResult call()
                         throws Exception
                     {
-                        DefaultReporterFactory reporter = new DefaultReporterFactory( startupReportConfiguration, log );
+                        int forkNumber = drawNumber();
+                        DefaultReporterFactory reporter =
+                                new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
                         defaultReporterFactories.add( reporter );
-                        ForkClient forkClient =
-                                new ForkClient( reporter, testProvidingInputStream, log, printedErrorStream )
+                        ForkClient forkClient = new ForkClient( reporter, testProvidingInputStream, log,
+                                printedErrorStream, forkNumber )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -358,9 +365,16 @@ public class ForkStarter
                                 }
                             }
                         };
-
-                        return fork( null, new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
-                                 forkClient, effectiveSystemProperties, testProvidingInputStream, true );
+                        Map<String, String> providerProperties = providerConfiguration.getProviderProperties();
+                        try
+                        {
+                            return fork( null, new PropertiesWrapper( providerProperties ), forkClient,
+                                    effectiveSystemProperties, forkNumber, testProvidingInputStream, true );
+                        }
+                        finally
+                        {
+                            returnNumber( forkNumber );
+                        }
                     }
                 };
                 results.add( executorService.submit( pf ) );
@@ -408,11 +422,12 @@ public class ForkStarter
                     public RunResult call()
                         throws Exception
                     {
+                        int forkNumber = drawNumber();
                         DefaultReporterFactory forkedReporterFactory =
-                            new DefaultReporterFactory( startupReportConfiguration, log );
+                            new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
                         defaultReporterFactories.add( forkedReporterFactory );
                         ForkClient forkClient = new ForkClient( forkedReporterFactory, builder.getImmediateCommands(),
-                                log, printedErrorStream )
+                                log, printedErrorStream, forkNumber )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -428,10 +443,11 @@ public class ForkStarter
                         {
                             return fork( testSet,
                                          new PropertiesWrapper( providerConfiguration.getProviderProperties() ),
-                                         forkClient, effectiveSystemProperties, stream, false );
+                                         forkClient, effectiveSystemProperties, forkNumber, stream, false );
                         }
                         finally
                         {
+                            returnNumber( forkNumber );
                             builder.removeStream( stream );
                         }
                     }
@@ -522,24 +538,6 @@ public class ForkStarter
     }
 
     private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
-                            SurefireProperties effectiveSystemProperties,
-                            AbstractForkInputStream testProvidingInputStream, boolean readTestsFromInStream )
-        throws SurefireBooterForkException
-    {
-        int forkNumber = drawNumber();
-        forkClient.setForkNumber( forkNumber );
-        try
-        {
-            return fork( testSet, providerProperties, forkClient, effectiveSystemProperties, forkNumber,
-                         testProvidingInputStream, readTestsFromInStream );
-        }
-        finally
-        {
-            returnNumber( forkNumber );
-        }
-    }
-
-    private RunResult fork( Object testSet, KeyValueSource providerProperties, ForkClient forkClient,
                             SurefireProperties effectiveSystemProperties, int forkNumber,
                             AbstractForkInputStream testProvidingInputStream, boolean readTestsFromInStream )
         throws SurefireBooterForkException
@@ -553,7 +551,7 @@ public class ForkStarter
             BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
             Long pluginPid = forkConfiguration.getPluginPlatform().getPluginPid();
             surefireProperties = booterSerializer.serialize( providerProperties, providerConfiguration,
-                    startupConfiguration, testSet, readTestsFromInStream, pluginPid );
+                    startupConfiguration, testSet, readTestsFromInStream, pluginPid, forkNumber );
 
             log.debug( "Determined Maven Process ID " + pluginPid );
 
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 4871e2a..254111b 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
@@ -107,6 +107,8 @@ public class ForkClient
      */
     private final AtomicBoolean printedErrorStream;
 
+    private final int forkNumber;
+
     /**
      * Used by single Thread started by {@link ThreadedStreamConsumer} and therefore does not need to be volatile.
      */
@@ -119,15 +121,14 @@ public class ForkClient
 
     private volatile StackTraceWriter errorInFork;
 
-    private volatile int forkNumber;
-
     public ForkClient( DefaultReporterFactory defaultReporterFactory, NotifiableTestStream notifiableTestStream,
-                       ConsoleLogger log, AtomicBoolean printedErrorStream )
+                       ConsoleLogger log, AtomicBoolean printedErrorStream, int forkNumber )
     {
         this.defaultReporterFactory = defaultReporterFactory;
         this.notifiableTestStream = notifiableTestStream;
         this.log = log;
         this.printedErrorStream = printedErrorStream;
+        this.forkNumber = forkNumber;
     }
 
     protected void stopOnNextTest()
@@ -317,10 +318,11 @@ public class ForkClient
             String msg = "Corrupted STDOUT by directly writing to native stream in forked JVM " + forkNumber + ".";
 
             InPluginProcessDumpSingleton util = InPluginProcessDumpSingleton.getSingleton();
+            File reportsDir = defaultReporterFactory.getReportsDirectory();
             File dump =
                     e == null
-                    ? util.dumpText( msg + " Stream '" + event + "'.", defaultReporterFactory, forkNumber )
-                    : util.dumpException( e, msg + " Stream '" + event + "'.", defaultReporterFactory, forkNumber );
+                    ? util.dumpStreamText( msg + " Stream '" + event + "'.", reportsDir, forkNumber )
+                    : util.dumpStreamException( e, msg + " Stream '" + event + "'.", reportsDir, forkNumber );
 
             if ( printedErrorStream.compareAndSet( false, true ) )
             {
@@ -491,12 +493,6 @@ public class ForkClient
         return !testsInProgress.isEmpty();
     }
 
-    public void setForkNumber( int forkNumber )
-    {
-        assert this.forkNumber == 0;
-        this.forkNumber = forkNumber;
-    }
-
     private static final class OperationalData
     {
         private final byte operationId;
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/InPluginProcessDumpSingleton.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/InPluginProcessDumpSingleton.java
index 0676b52..d7bbe9f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/InPluginProcessDumpSingleton.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/InPluginProcessDumpSingleton.java
@@ -19,14 +19,15 @@ package org.apache.maven.plugin.surefire.booterclient.output;
  * under the License.
  */
 
-import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
 import org.apache.maven.surefire.util.internal.DumpFileUtils;
 
 import java.io.File;
 
 import static java.lang.String.format;
+import static org.apache.maven.plugin.surefire.SurefireHelper.DUMP_FILENAME;
+import static org.apache.maven.plugin.surefire.SurefireHelper.DUMP_FILENAME_FORMATTER;
+import static org.apache.maven.plugin.surefire.SurefireHelper.DUMPSTREAM_FILENAME;
 import static org.apache.maven.plugin.surefire.SurefireHelper.DUMPSTREAM_FILENAME_FORMATTER;
-import static org.apache.maven.surefire.booter.DumpErrorSingleton.DUMPSTREAM_FILE_EXT;
 
 /**
  * Reports errors to dump file.
@@ -36,8 +37,6 @@ public final class InPluginProcessDumpSingleton
 {
     private static final InPluginProcessDumpSingleton SINGLETON = new InPluginProcessDumpSingleton();
 
-    private final String creationDate = DumpFileUtils.newFormattedDateFileName();
-
     private InPluginProcessDumpSingleton()
     {
     }
@@ -47,45 +46,59 @@ public final class InPluginProcessDumpSingleton
         return SINGLETON;
     }
 
-    public synchronized File dumpException( Throwable t, String msg, DefaultReporterFactory defaultReporterFactory,
-                                            int jvmRun )
+    public synchronized File dumpStreamException( Throwable t, String msg, File reportsDirectory, int jvmRun )
     {
-        File dump = newDumpFile( defaultReporterFactory, jvmRun );
+        File dump = newDumpStreamFile( reportsDirectory, jvmRun );
         DumpFileUtils.dumpException( t, msg == null ? "null" : msg, dump );
         return dump;
     }
 
-    public synchronized void dumpException( Throwable t, String msg, DefaultReporterFactory defaultReporterFactory )
+    public synchronized void dumpStreamException( Throwable t, String msg, File reportsDirectory )
     {
-        DumpFileUtils.dumpException( t, msg == null ? "null" : msg, newDumpFile( defaultReporterFactory ) );
+        DumpFileUtils.dumpException( t, msg == null ? "null" : msg, newDumpStreamFile( reportsDirectory ) );
     }
 
-    public synchronized void dumpException( Throwable t, DefaultReporterFactory defaultReporterFactory )
+    public synchronized File dumpStreamText( String msg, File reportsDirectory, int jvmRun )
     {
-        DumpFileUtils.dumpException( t, newDumpFile( defaultReporterFactory ) );
+        File dump = newDumpStreamFile( reportsDirectory, jvmRun );
+        DumpFileUtils.dumpText( msg == null ? "null" : msg, dump );
+        return dump;
     }
 
-    public synchronized File dumpText( String msg, DefaultReporterFactory defaultReporterFactory, int jvmRun )
+    public synchronized void dumpStreamText( String msg, File reportsDirectory )
     {
-        File dump = newDumpFile( defaultReporterFactory, jvmRun );
-        DumpFileUtils.dumpText( msg == null ? "null" : msg, dump );
-        return dump;
+        DumpFileUtils.dumpText( msg == null ? "null" : msg, newDumpStreamFile( reportsDirectory ) );
+    }
+
+    public synchronized void dumpException( Throwable t, String msg, File reportsDirectory, int jvmRun )
+    {
+        File dump = newDumpFile( reportsDirectory, jvmRun );
+        DumpFileUtils.dumpException( t, msg == null ? "null" : msg, dump );
     }
 
-    public synchronized void dumpText( String msg, DefaultReporterFactory defaultReporterFactory )
+    public synchronized void dumpException( Throwable t, String msg, File reportsDirectory )
     {
-        DumpFileUtils.dumpText( msg == null ? "null" : msg, newDumpFile( defaultReporterFactory ) );
+        File dump = newDumpFile( reportsDirectory );
+        DumpFileUtils.dumpException( t, msg == null ? "null" : msg, dump );
     }
 
-    private File newDumpFile( DefaultReporterFactory defaultReporterFactory )
+    private File newDumpStreamFile( File reportsDirectory )
     {
-        File reportsDirectory = defaultReporterFactory.getReportsDirectory();
-        return new File( reportsDirectory, creationDate + DUMPSTREAM_FILE_EXT );
+        return new File( reportsDirectory, DUMPSTREAM_FILENAME );
     }
 
-    private static File newDumpFile( DefaultReporterFactory defaultReporterFactory, int jvmRun )
+    private static File newDumpStreamFile( File reportsDirectory, int jvmRun )
     {
-        File reportsDirectory = defaultReporterFactory.getReportsDirectory();
         return new File( reportsDirectory, format( DUMPSTREAM_FILENAME_FORMATTER, jvmRun ) );
     }
+
+    private static File newDumpFile( File reportsDirectory, int jvmRun )
+    {
+        return new File( reportsDirectory, format( DUMP_FILENAME_FORMATTER, jvmRun ) );
+    }
+
+    private static File newDumpFile( File reportsDirectory )
+    {
+        return new File( reportsDirectory, DUMP_FILENAME );
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
index d460583..ace4f8a 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
@@ -42,6 +42,7 @@ public final class NativeStdErrStreamConsumer
     @Override
     public void consumeLine( String line )
     {
-        InPluginProcessDumpSingleton.getSingleton().dumpText( line, defaultReporterFactory );
+        InPluginProcessDumpSingleton.getSingleton()
+                .dumpStreamText( line, defaultReporterFactory.getReportsDirectory() );
     }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
index bbbd9c4..5bce92a 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
@@ -19,6 +19,9 @@ package org.apache.maven.plugin.surefire.report;
  * under the License.
  */
 
+import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
+import org.apache.maven.surefire.report.ReportEntry;
+
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -27,9 +30,6 @@ import java.io.IOException;
 import java.util.concurrent.atomic.AtomicStampedReference;
 import java.util.concurrent.locks.ReentrantLock;
 
-import org.apache.maven.surefire.booter.DumpErrorSingleton;
-import org.apache.maven.surefire.report.ReportEntry;
-
 import static org.apache.maven.plugin.surefire.report.FileReporter.getReportFile;
 
 /**
@@ -48,6 +48,7 @@ public class ConsoleOutputFileReporter
 
     private final File reportsDirectory;
     private final String reportNameSuffix;
+    private final Integer forkNumber;
 
     private final AtomicStampedReference<FilterOutputStream> fileOutputStream =
             new AtomicStampedReference<FilterOutputStream>( null, OPEN );
@@ -56,10 +57,11 @@ public class ConsoleOutputFileReporter
 
     private volatile String reportEntryName;
 
-    public ConsoleOutputFileReporter( File reportsDirectory, String reportNameSuffix )
+    public ConsoleOutputFileReporter( File reportsDirectory, String reportNameSuffix, Integer forkNumber )
     {
         this.reportsDirectory = reportsDirectory;
         this.reportNameSuffix = reportNameSuffix;
+        this.forkNumber = forkNumber;
     }
 
     @Override
@@ -124,9 +126,7 @@ public class ConsoleOutputFileReporter
         }
         catch ( IOException e )
         {
-            DumpErrorSingleton.getSingleton()
-                    .dumpException( e );
-
+            dumpException( e );
             throw new RuntimeException( e );
         }
         finally
@@ -143,10 +143,9 @@ public class ConsoleOutputFileReporter
             // close null-output.txt report file
             close( true );
         }
-        catch ( IOException ignored )
+        catch ( IOException e )
         {
-            DumpErrorSingleton.getSingleton()
-                    .dumpException( ignored );
+            dumpException( e );
         }
         finally
         {
@@ -162,10 +161,9 @@ public class ConsoleOutputFileReporter
         {
             close( false );
         }
-        catch ( IOException ignored )
+        catch ( IOException e )
         {
-            DumpErrorSingleton.getSingleton()
-                    .dumpException( ignored );
+            dumpException( e );
         }
     }
 
@@ -183,4 +181,18 @@ public class ConsoleOutputFileReporter
             }
         }
     }
+
+    private void dumpException( IOException e )
+    {
+        if ( forkNumber == null )
+        {
+            InPluginProcessDumpSingleton.getSingleton()
+                    .dumpException( e, e.getLocalizedMessage(), reportsDirectory );
+        }
+        else
+        {
+            InPluginProcessDumpSingleton.getSingleton()
+                    .dumpException( e, e.getLocalizedMessage(), reportsDirectory, forkNumber );
+        }
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java
index 15b4306..1fd2bfe 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java
@@ -63,9 +63,10 @@ import static org.apache.maven.surefire.util.internal.ObjectUtils.useNonNull;
 public class DefaultReporterFactory
     implements ReporterFactory
 {
+    private final Collection<TestSetRunListener> listeners = new ConcurrentLinkedQueue<TestSetRunListener>();
     private final StartupReportConfiguration reportConfiguration;
     private final ConsoleLogger consoleLogger;
-    private final Collection<TestSetRunListener> listeners;
+    private final Integer forkNumber;
 
     private RunStatistics globalStats = new RunStatistics();
 
@@ -80,9 +81,15 @@ public class DefaultReporterFactory
 
     public DefaultReporterFactory( StartupReportConfiguration reportConfiguration, ConsoleLogger consoleLogger )
     {
+        this( reportConfiguration, consoleLogger, null );
+    }
+
+    public DefaultReporterFactory( StartupReportConfiguration reportConfiguration, ConsoleLogger consoleLogger,
+                                   Integer forkNumber )
+    {
         this.reportConfiguration = reportConfiguration;
         this.consoleLogger = consoleLogger;
-        listeners = new ConcurrentLinkedQueue<TestSetRunListener>();
+        this.forkNumber = forkNumber;
     }
 
     @Override
@@ -113,26 +120,24 @@ public class DefaultReporterFactory
 
     private FileReporter createFileReporter()
     {
-        final FileReporter fileReporter = reportConfiguration.instantiateFileReporter();
+        FileReporter fileReporter = reportConfiguration.instantiateFileReporter( forkNumber );
         return useNonNull( fileReporter, NullFileReporter.INSTANCE );
     }
 
     private StatelessXmlReporter createSimpleXMLReporter()
     {
-        final StatelessXmlReporter xmlReporter = reportConfiguration.instantiateStatelessXmlReporter();
+        StatelessXmlReporter xmlReporter = reportConfiguration.instantiateStatelessXmlReporter( forkNumber );
         return useNonNull( xmlReporter, NullStatelessXmlReporter.INSTANCE );
     }
 
     private TestcycleConsoleOutputReceiver createConsoleOutputReceiver()
     {
-        final TestcycleConsoleOutputReceiver consoleOutputReceiver =
-                reportConfiguration.instantiateConsoleOutputFileReporter();
-        return useNonNull( consoleOutputReceiver, NullConsoleOutputReceiver.INSTANCE );
+        return reportConfiguration.instantiateConsoleOutputFileReporter( forkNumber );
     }
 
     private StatisticsReporter createStatisticsReporter()
     {
-        final StatisticsReporter statisticsReporter = reportConfiguration.getStatisticsReporter();
+        StatisticsReporter statisticsReporter = reportConfiguration.getStatisticsReporter();
         return useNonNull( statisticsReporter, NullStatisticsReporter.INSTANCE );
     }
 
@@ -147,10 +152,7 @@ public class DefaultReporterFactory
     {
         for ( DefaultReporterFactory factory : factories )
         {
-            for ( TestSetRunListener listener : factory.listeners )
-            {
-                listeners.add( listener );
-            }
+            listeners.addAll( factory.listeners );
         }
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java
deleted file mode 100644
index 327c77d..0000000
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/NullConsoleOutputReceiver.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.maven.plugin.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 org.apache.maven.surefire.report.ReportEntry;
-
-/**
- * ConsoleReporter doing nothing rather than using null.
- *
- * @author <a href="mailto:britter@apache.org">Benedikt Ritter</a>
- * @since 2.20
- */
-class NullConsoleOutputReceiver
-    implements TestcycleConsoleOutputReceiver
-{
-
-    static final NullConsoleOutputReceiver INSTANCE = new NullConsoleOutputReceiver();
-
-    private NullConsoleOutputReceiver()
-    {
-    }
-
-    @Override
-    public void testSetStarting( ReportEntry reportEntry )
-    {
-    }
-
-    @Override
-    public void testSetCompleted( ReportEntry report )
-    {
-    }
-
-    @Override
-    public void close()
-    {
-    }
-
-    @Override
-    public void writeTestOutput( byte[] buf, int off, int len, boolean stdout )
-    {
-    }
-}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
index c00f7f9..40ab309 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
@@ -21,6 +21,7 @@ package org.apache.maven.plugin.surefire;
 
 import org.junit.Test;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -37,15 +38,36 @@ import static org.junit.Assume.assumeTrue;
 public class SurefireHelperTest
 {
     @Test
+    public void shouldReplaceForkNumberPath()
+    {
+        File root = new File( System.getProperty( "user.dir", "" ) );
+        File pathWithPlaceholder = new File( root, "${surefire.forkNumber}" );
+        File changed = SurefireHelper.replaceForkThreadsInPath( pathWithPlaceholder, 5 );
+        assertThat( changed.getPath() )
+                .isEqualTo( new File( root, "5" ).getPath() );
+    }
+
+    @Test
+    public void shouldReplaceLongForkNumberPath()
+    {
+        File root = new File( System.getProperty( "user.dir", "" ) );
+        File subDir = new File( root, "reports-${surefire.forkNumber}" );
+        File pathWithPlaceholder = new File( subDir, "subfolder" );
+        File changed = SurefireHelper.replaceForkThreadsInPath( pathWithPlaceholder, 5 );
+        assertThat( changed.getPath() )
+                .isEqualTo( new File( new File( root, "reports-5" ), "subfolder" ).getPath() );
+    }
+
+    @Test
     public void shouldBeThreeDumpFiles()
     {
         String[] dumps = SurefireHelper.getDumpFilesToPrint();
-        assertThat( dumps ).hasSize( 3 );
+        assertThat( dumps ).hasSize( 4 );
         assertThat( dumps ).doesNotHaveDuplicates();
         List<String> onlyStrings = new ArrayList<String>();
         addAll( onlyStrings, dumps );
         onlyStrings.removeAll( singleton( (String) null ) );
-        assertThat( onlyStrings ).hasSize( 3 );
+        assertThat( onlyStrings ).hasSize( 4 );
     }
 
     @Test
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
index 26b8be7..4777ce8 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerProviderConfigurationTest.java
@@ -220,7 +220,7 @@ public class BooterDeserializerProviderConfigurationTest
             test = "aTest";
         }
         final File propsTest = booterSerializer.serialize( props, booterConfiguration, testProviderConfiguration, test,
-                                                           readTestsFromInStream, 51L );
+                                                           readTestsFromInStream, 51L, 1 );
         BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
         assertEquals( 51L, (Object) booterDeserializer.getPluginPid() );
         return booterDeserializer.deserialize();
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
index fc00bcd..7a1a7e2 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -125,8 +125,8 @@ public class BooterDeserializerStartupConfigurationTest
         PropertiesWrapper props = new PropertiesWrapper( new HashMap<String, String>() );
         BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration );
         String aTest = "aTest";
-        final File propsTest =
-            booterSerializer.serialize( props, getProviderConfiguration(), startupConfiguration, aTest, false, null );
+        File propsTest = booterSerializer.serialize( props, getProviderConfiguration(), startupConfiguration, aTest,
+                false, null, 1 );
         BooterDeserializer booterDeserializer = new BooterDeserializer( new FileInputStream( propsTest ) );
         assertNull( booterDeserializer.getPluginPid() );
         return booterDeserializer.getProviderConfiguration();
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 7d2e6be..0fd275f 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
@@ -223,7 +223,7 @@ public class ForkingRunListenerTest
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
         NullConsoleLogger log = new NullConsoleLogger();
         ForkClient forkStreamClient =
-                new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null );
+                new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null, 1 );
 
         forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
@@ -248,7 +248,7 @@ public class ForkingRunListenerTest
         TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
         NullConsoleLogger log = new NullConsoleLogger();
         ForkClient forkStreamClient =
-                new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null );
+                new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null, 1 );
 
         forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
@@ -277,7 +277,7 @@ public class ForkingRunListenerTest
         NotifiableTestStream notifiableTestStream = new MockNotifiableTestStream();
         NullConsoleLogger log = new NullConsoleLogger();
 
-        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null );
+        ForkClient forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null, 1 );
         forkStreamClient.consumeMultiLineContent( content.toString( "UTF-8" ) );
 
         MockReporter reporter = (MockReporter) forkStreamClient.getReporter();
@@ -285,7 +285,7 @@ public class ForkingRunListenerTest
         Assert.assertEquals( expected, reporter.getFirstData() );
         Assert.assertEquals( 1, reporter.getEvents().size() );
 
-        forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null );
+        forkStreamClient = new ForkClient( providerReporterFactory, notifiableTestStream, log, null, 2 );
         forkStreamClient.consumeMultiLineContent( anotherContent.toString( "UTF-8" ) );
         MockReporter reporter2 = (MockReporter) forkStreamClient.getReporter();
         Assert.assertEquals( MockReporter.TEST_SKIPPED, reporter2.getFirstEvent() );
@@ -355,7 +355,7 @@ public class ForkingRunListenerTest
             TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
             NullConsoleLogger log = new NullConsoleLogger();
             final ForkClient forkStreamClient =
-                    new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null );
+                    new ForkClient( providerReporterFactory, new MockNotifiableTestStream(), log, null, 1 );
             forkStreamClient.consumeMultiLineContent( content.toString( ) );
             reporter = (MockReporter) forkStreamClient.getReporter();
         }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
index df011d9..2ee6186 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/report/ConsoleOutputFileReporterTest.java
@@ -46,7 +46,7 @@ public class ConsoleOutputFileReporterTest
         //noinspection ResultOfMethodCallIgnored
         reportDir.mkdirs();
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), getClass().getName() );
-        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null );
+        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null, null );
         reporter.testSetStarting( reportEntry );
         reporter.writeTestOutput( "some text".getBytes( US_ASCII ), 0, 5, true );
         reporter.testSetCompleted( reportEntry );
@@ -74,7 +74,7 @@ public class ConsoleOutputFileReporterTest
         reportDir.mkdirs();
         String suffixText = "sampleSuffixText";
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), getClass().getName() );
-        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, suffixText );
+        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, suffixText, null );
         reporter.testSetStarting( reportEntry );
         reporter.writeTestOutput( "some text".getBytes( US_ASCII ), 0, 5, true );
         reporter.testSetCompleted( reportEntry );
@@ -97,7 +97,7 @@ public class ConsoleOutputFileReporterTest
         File reportDir = new File( new File( System.getProperty( "user.dir" ), "target" ), "tmp3" );
         //noinspection ResultOfMethodCallIgnored
         reportDir.mkdirs();
-        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null );
+        ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null, null );
         reporter.writeTestOutput( "some text".getBytes( US_ASCII ), 0, 5, true );
         reporter.testSetCompleted( new SimpleReportEntry( getClass().getName(), getClass().getName() ) );
         reporter.close();
@@ -119,7 +119,7 @@ public class ConsoleOutputFileReporterTest
         File reportDir = new File( new File( System.getProperty( "user.dir" ), "target" ), "tmp4" );
         //noinspection ResultOfMethodCallIgnored
         reportDir.mkdirs();
-        final ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null );
+        final ConsoleOutputFileReporter reporter = new ConsoleOutputFileReporter( reportDir, null, null );
         reporter.testSetStarting( new SimpleReportEntry( getClass().getName(), getClass().getName() ) );
         ExecutorService scheduler = Executors.newFixedThreadPool( 10 );
         final ArrayList<Callable<Void>> jobs = new ArrayList<Callable<Void>>();
diff --git a/maven-surefire-plugin/src/site/fml/faq.fml b/maven-surefire-plugin/src/site/fml/faq.fml
index b73dde6..96053cf 100644
--- a/maven-surefire-plugin/src/site/fml/faq.fml
+++ b/maven-surefire-plugin/src/site/fml/faq.fml
@@ -130,6 +130,7 @@ under the License.
         <![CDATA[ [date]-jvmRun[N].dump]]><br/>
         <![CDATA[ [date]-jvmRun[N].dumpstream]]><br/>
         <![CDATA[ [date].dumpstream]]><br/>
+        <![CDATA[ [date].dump]]><br/>
         </code>
 
         Forked JVM process and plugin process communicate via std/out. If this channel is corrupted, for a whatever
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DumpErrorSingleton.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/DumpErrorSingleton.java
index e287f05..97e37d0 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/DumpErrorSingleton.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/DumpErrorSingleton.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
-import org.apache.maven.surefire.report.ReporterConfiguration;
 import org.apache.maven.surefire.util.internal.DumpFileUtils;
 
 import java.io.File;
@@ -51,10 +50,10 @@ public final class DumpErrorSingleton
         return SINGLETON;
     }
 
-    public synchronized void init( String dumpFileName, ReporterConfiguration configuration )
+    public synchronized void init( File reportsDir, String dumpFileName )
     {
-        dumpFile = createDumpFile( dumpFileName, configuration );
-        dumpStreamFile = createDumpStreamFile( dumpFileName, configuration );
+        dumpFile = createDumpFile( reportsDir, dumpFileName );
+        dumpStreamFile = createDumpStreamFile( reportsDir, dumpFileName );
     }
 
     public synchronized void dumpException( Throwable t, String msg )
@@ -87,13 +86,13 @@ public final class DumpErrorSingleton
         DumpFileUtils.dumpText( msg == null ? "null" : msg, dumpStreamFile );
     }
 
-    private File createDumpFile( String dumpFileName, ReporterConfiguration configuration )
+    private File createDumpFile( File reportsDir, String dumpFileName )
     {
-        return newDumpFile( dumpFileName + DUMP_FILE_EXT, configuration );
+        return newDumpFile( reportsDir, dumpFileName + DUMP_FILE_EXT );
     }
 
-    private File createDumpStreamFile( String dumpFileName, ReporterConfiguration configuration )
+    private File createDumpStreamFile( File reportsDir, String dumpFileName )
     {
-        return newDumpFile( dumpFileName + DUMPSTREAM_FILE_EXT, configuration );
+        return newDumpFile( reportsDir, dumpFileName + DUMPSTREAM_FILE_EXT );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DumpFileUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DumpFileUtils.java
index c83ae1f..cc2d04a 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DumpFileUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/DumpFileUtils.java
@@ -19,8 +19,6 @@ package org.apache.maven.surefire.util.internal;
  * under the License.
  */
 
-import org.apache.maven.surefire.report.ReporterConfiguration;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -49,12 +47,12 @@ public final class DumpFileUtils
     /**
      * New dump file. Synchronized object appears in main memory and perfectly visible in other threads.
      *
+     * @param reportsDir    only report directory
      * @param dumpFileName    dump file name
-     * @param configuration    only report directory
      */
-    public static synchronized File newDumpFile( String dumpFileName, ReporterConfiguration configuration )
+    public static synchronized File newDumpFile( File reportsDir, String dumpFileName )
     {
-        return new File( configuration.getReportsDirectory(), dumpFileName );
+        return new File( reportsDir, dumpFileName );
     }
 
     public static void dumpException( Throwable t, File dumpFile )
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
index bbb3294..03ef036 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -95,7 +95,8 @@ public final class ForkedBooter
         setSystemProperties( new File( tmpDir, effectiveSystemPropertiesFileName ) );
 
         providerConfiguration = booterDeserializer.deserialize();
-        DumpErrorSingleton.getSingleton().init( dumpFileName, providerConfiguration.getReporterConfiguration() );
+        DumpErrorSingleton.getSingleton()
+                .init( providerConfiguration.getReporterConfiguration().getReportsDirectory(), dumpFileName );
 
         startupConfiguration = booterDeserializer.getProviderConfiguration();
         systemExitTimeoutInSeconds = providerConfiguration.systemExitTimeout( DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
index f68eb35..abf17cb 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java
@@ -31,8 +31,10 @@ import java.util.List;
 import org.apache.commons.io.FileUtils;
 
 import junit.framework.Assert;
+import org.hamcrest.Matcher;
 
 import static junit.framework.Assert.assertTrue;
+import static org.hamcrest.Matchers.containsString;
 
 /**
  * @author Kristian Rosenvold
@@ -129,12 +131,12 @@ public class TestFile
         return file.isFile();
     }
 
-    public TestFile assertContainsText( String text )
+    public TestFile assertContainsText( Matcher<String> matcher )
     {
         final List<String> list = surefireVerifier.loadFile( file, encoding );
         for ( String line : list )
         {
-            if ( line.contains( text ) )
+            if ( matcher.matches( line ) )
             {
                 return this;
             }
@@ -143,6 +145,11 @@ public class TestFile
         return null;
     }
 
+    public TestFile assertContainsText( String text )
+    {
+        return assertContainsText( containsString( text ) );
+    }
+
     public URI toURI()
     {
         return file.toURI();
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1535TestNGParallelSuitesIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1535TestNGParallelSuitesIT.java
index a3ffd5b..0c8061d 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1535TestNGParallelSuitesIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1535TestNGParallelSuitesIT.java
@@ -19,20 +19,125 @@ package org.apache.maven.surefire.its.jiras;
  * under the License.
  */
 
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.surefire.its.fixture.OutputValidator;
 import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.apache.maven.surefire.its.fixture.TestFile;
 import org.junit.Test;
 
+import java.nio.charset.Charset;
+
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+
 public class Surefire1535TestNGParallelSuitesIT
         extends SurefireJUnit4IntegrationTestCase
 {
+    private static final Charset UTF8 = Charset.forName( "UTF-8" );
+
+    @Test
+    public void forks2() throws VerificationException
+    {
+        OutputValidator validator = unpack()
+                .activateProfile( "forked-reports-directory" )
+                .forkCount( 2 )
+                .executeTest();
+
+        TestFile testFile = validator.getSurefireReportsFile( "../surefire-reports-1/TEST-TestSuite.xml", UTF8 );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest" );
+
+        testFile = validator.getSurefireReportsFile( "../surefire-reports-2/TEST-TestSuite.xml", UTF8 );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest" );
+
+        validator.assertThatLogLine( containsString( "Tests run: 2, Failures: 0, Errors: 0, Skipped: 0" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, " ), is( 2 ) )
+                .assertThatLogLine( containsString( "Suite1.xml" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Suite2.xml" ), is( 1 ) )
+                .assertThatLogLine( containsString( "test 1" ), is( 1 ) )
+                .assertThatLogLine( containsString( "test 2" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Running TestSuite" ), is( 2 ) );
+    }
+
     @Test
-    public void testParallelSuites()
+    public void forks2Redirected() throws VerificationException
+    {
+        OutputValidator validator = unpack()
+                .activateProfile( "forked-reports-directory" )
+                .forkCount( 2 )
+                .redirectToFile( true )
+                .executeTest();
+
+        TestFile testFile = validator.getSurefireReportsFile( "../surefire-reports-1/TEST-TestSuite.xml", UTF8 );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest" );
+
+        testFile = validator.getSurefireReportsFile( "../surefire-reports-2/TEST-TestSuite.xml", UTF8 );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest" );
+
+        validator.assertThatLogLine( containsString( "Tests run: 2, Failures: 0, Errors: 0, Skipped: 0" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, " ), is( 2 ) )
+                .assertThatLogLine( containsString( "Running TestSuite" ), is( 2 ) );
+
+        TestFile outFile = validator.getSurefireReportsFile( "../surefire-reports-1/TestSuite-output.txt" );
+        outFile.assertFileExists();
+        outFile.assertContainsText( anyOf( containsString( "Suite1.xml" ), containsString( "Suite2.xml" ) ) );
+        outFile.assertContainsText( anyOf( containsString( "test 1" ), containsString( "test 2" ) ) );
+
+        outFile = validator.getSurefireReportsFile( "../surefire-reports-2/TestSuite-output.txt" );
+        outFile.assertFileExists();
+        outFile.assertContainsText( anyOf( containsString( "Suite1.xml" ), containsString( "Suite2.xml" ) ) );
+        outFile.assertContainsText( anyOf( containsString( "test 1" ), containsString( "test 2" ) ) );
+    }
+
+    @Test
+    public void forks0() throws VerificationException
+    {
+        OutputValidator validator = unpack()
+                .forkCount( 0 )
+                .executeTest();
+
+        TestFile testFile = validator.getSurefireReportsFile( "TEST-TestSuite.xml" );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest1\"" );
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest2\"" );
+
+        validator.assertThatLogLine( containsString( "Suite1.xml" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Suite2.xml" ), is( 1 ) )
+                .assertThatLogLine( containsString( "test 1" ), is( 1 ) )
+                .assertThatLogLine( containsString( "test 2" ), is( 1 ) )
+                .assertThatLogLine( containsString( "Running TestSuite" ), is( 1 ) );
+    }
+
+    @Test
+    public void forks0Redirected() throws VerificationException
+    {
+        OutputValidator validator = unpack()
+                .forkCount( 0 )
+                .redirectToFile( true )
+                .executeTest();
+
+        TestFile testFile = validator.getSurefireReportsXmlFile( "TEST-TestSuite.xml" );
+        testFile.assertFileExists();
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest1\"" );
+        testFile.assertContainsText( "<testcase name=\"test\" classname=\"it.ParallelTest2\"" );
+
+        validator.assertThatLogLine( containsString( "Running TestSuite" ), is( 1 ) );
+
+        TestFile outFile = validator.getSurefireReportsFile( "TestSuite-output.txt" );
+        outFile.assertFileExists();
+        outFile.assertContainsText( "Suite1.xml" );
+        outFile.assertContainsText( "Suite1.xml" );
+        outFile.assertContainsText( "test 1" );
+        outFile.assertContainsText( "test 2" );
+    }
+
+    private SurefireLauncher unpack()
     {
-        unpack("/surefire-1535-parallel-testng")
-                .maven()
-                .sysProp( "testNgVersion", "5.7" )
-                .sysProp( "testNgClassifier", "jdk15" )
-                .executeTest()
-                .assertTestSuiteResults( 2, 0, 0, 0 );
+        return unpack("/surefire-1535-parallel-testng");
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-1535-parallel-testng/pom.xml b/surefire-its/src/test/resources/surefire-1535-parallel-testng/pom.xml
index 942ddb6..c7aba88 100644
--- a/surefire-its/src/test/resources/surefire-1535-parallel-testng/pom.xml
+++ b/surefire-its/src/test/resources/surefire-1535-parallel-testng/pom.xml
@@ -33,33 +33,30 @@
         <maven.compiler.target>1.6</maven.compiler.target>
     </properties>
 
+    <dependencies>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>5.7</version>
+            <classifier>jdk15</classifier>
+        </dependency>
+    </dependencies>
+
     <profiles>
         <profile>
-            <id>testng-old</id>
-            <activation>
-                <property><name>testNgClassifier</name></property>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.testng</groupId>
-                    <artifactId>testng</artifactId>
-                    <version>${testNgVersion}</version>
-                    <classifier>${testNgClassifier}</classifier>
-                </dependency>
-            </dependencies>
-        </profile>
-        <profile>
-            <id>testng-new</id>
-            <activation>
-                <property><name>!testNgClassifier</name></property>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.testng</groupId>
-                    <artifactId>testng</artifactId>
-                    <version>${testNgVersion}</version>
-                </dependency>
-            </dependencies>
+            <id>forked-reports-directory</id>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <artifactId>maven-surefire-plugin</artifactId>
+                            <configuration>
+                                <reportsDirectory>target/surefire-reports-${surefire.forkNumber}</reportsDirectory>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
         </profile>
     </profiles>
 
@@ -69,7 +66,6 @@
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>${surefire.version}</version>
                 <configuration>
-                    <forkCount>2</forkCount>
                     <reuseForks>false</reuseForks>
                     <suiteXmlFiles>
                         <suiteXmlFile>src/test/resources/Suite1.xml</suiteXmlFile>
diff --git a/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest1.java b/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest1.java
index 177c420..0590851 100644
--- a/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest1.java
+++ b/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest1.java
@@ -29,6 +29,7 @@ public class ParallelTest1
 {
     public void test() throws Exception
     {
+        System.out.println( "test 1" );
         TimeUnit.SECONDS.sleep( 1L );
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest2.java b/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest2.java
index d56fa62..8467ea7 100644
--- a/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest2.java
+++ b/surefire-its/src/test/resources/surefire-1535-parallel-testng/src/test/java/it/ParallelTest2.java
@@ -29,6 +29,7 @@ public class ParallelTest2
 {
     public void test() throws Exception
     {
+        System.out.println( "test 2" );
         TimeUnit.SECONDS.sleep( 1L );
     }
 }