You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rm...@apache.org on 2020/07/08 11:02:49 UTC

[maven-surefire] branch rmannibucau/flush-output-toggle created (now 7be86d1)

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

rmannibucau pushed a change to branch rmannibucau/flush-output-toggle
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.


      at 7be86d1  enable to flush regularly output of the forked process

This branch includes the following new commits:

     new 7be86d1  enable to flush regularly output of the forked process

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



[maven-surefire] 01/01: enable to flush regularly output of the forked process

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

rmannibucau pushed a commit to branch rmannibucau/flush-output-toggle
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit 7be86d1ee9c7992dc7a48a218ac4318c320c2b1b
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Wed Jul 8 13:02:23 2020 +0200

    enable to flush regularly output of the forked process
---
 .../plugin/surefire/AbstractSurefireMojo.java      | 15 +++++++-
 .../surefire/booterclient/BooterSerializer.java    |  5 +++
 ...ooterDeserializerProviderConfigurationTest.java |  2 +-
 ...BooterDeserializerStartupConfigurationTest.java |  2 +-
 .../AbstractNoninterruptibleWritableChannel.java   |  6 +++
 .../util/internal/WritableBufferedByteChannel.java |  2 +
 .../maven/surefire/booter/BooterConstants.java     |  1 +
 .../maven/surefire/booter/BooterDeserializer.java  |  4 +-
 .../apache/maven/surefire/booter/ForkedBooter.java | 45 ++++++++++++++++++++++
 .../surefire/booter/ProviderConfiguration.java     | 10 ++++-
 .../spi/LegacyMasterProcessChannelEncoder.java     |  5 +++
 11 files changed, 92 insertions(+), 5 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 38d34fb..0f92bbf 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
@@ -809,6 +809,18 @@ public abstract class AbstractSurefireMojo
     private Map<String, String> jdkToolchain;
 
     /**
+     * How often output is forced to be flushed.
+     * Useful when there is no output for N ms but some data are buffered.
+     * It will trigger a flush each configured interval to ensure
+     * data don't stay blocked in a buffer.
+     * Setting it to 0 disable that feature.
+     *
+     * @since 3.0.0-M6
+     */
+    @Parameter( defaultValue = "0" )
+    private long outputFlushInterval;
+
+    /**
      *
      */
     @Component
@@ -1850,7 +1862,8 @@ public abstract class AbstractSurefireMojo
                                           testSuiteDefinition, providerProperties, null,
                                           false, cli, getSkipAfterFailureCount(),
                                           Shutdown.parameterOf( getShutdown() ),
-                                          getForkedProcessExitTimeoutInSeconds() );
+                                          getForkedProcessExitTimeoutInSeconds(),
+                                          outputFlushInterval );
     }
 
     private static Map<String, String> toStringProperties( Properties properties )
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 c8aee3c..6e62079 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
@@ -53,6 +53,7 @@ import static org.apache.maven.surefire.booter.BooterConstants.FORKTESTSET_PREFE
 import static org.apache.maven.surefire.booter.BooterConstants.INCLUDES_PROPERTY_PREFIX;
 import static org.apache.maven.surefire.booter.BooterConstants.ISTRIMSTACKTRACE;
 import static org.apache.maven.surefire.booter.BooterConstants.MAIN_CLI_OPTIONS;
+import static org.apache.maven.surefire.booter.BooterConstants.OUTPUT_FLUSH_INTERVAL_MS;
 import static org.apache.maven.surefire.booter.BooterConstants.PLUGIN_PID;
 import static org.apache.maven.surefire.booter.BooterConstants.PROCESS_CHECKER;
 import static org.apache.maven.surefire.booter.BooterConstants.PROVIDER_CONFIGURATION;
@@ -181,6 +182,10 @@ class BooterSerializer
             properties.addList( mainCliOptions, MAIN_CLI_OPTIONS );
         }
         properties.setNullableProperty( SYSTEM_EXIT_TIMEOUT, toString( providerConfiguration.getSystemExitTimeout() ) );
+        properties.setNullableProperty(
+            OUTPUT_FLUSH_INTERVAL_MS,
+            providerConfiguration.getOutputFlushInterval() == null
+                ? "0" : toString( providerConfiguration.getOutputFlushInterval() ) );
 
         File surefireTmpDir = forkConfiguration.getTempDirectory();
         boolean debug = forkConfiguration.isDebug();
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 7a08390..e62d1c3 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
@@ -279,7 +279,7 @@ public class BooterDeserializerProviderConfigurationTest
         RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, null );
         return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, true, reporterConfiguration,
                 new TestArtifactInfo( "5.0", "ABC" ), testSuiteDefinition, new HashMap<String, String>(), TEST_TYPED,
-                readTestsFromInStream, cli, 0, Shutdown.DEFAULT, 0 );
+                readTestsFromInStream, cli, 0, Shutdown.DEFAULT, 0, 0L );
     }
 
     private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
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 669e73c..cfa9f55 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
@@ -200,7 +200,7 @@ public class BooterDeserializerStartupConfigurationTest
         RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, null );
         return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, true, reporterConfiguration,
                 new TestArtifactInfo( "5.0", "ABC" ), testSuiteDefinition, new HashMap<String, String>(),
-                BooterDeserializerProviderConfigurationTest.TEST_TYPED, true, cli, 0, Shutdown.DEFAULT, 0 );
+                BooterDeserializerProviderConfigurationTest.TEST_TYPED, true, cli, 0, Shutdown.DEFAULT, 0, 0L );
     }
 
     private StartupConfiguration getTestStartupConfiguration( ClassLoaderConfiguration classLoaderConfiguration )
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/AbstractNoninterruptibleWritableChannel.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/AbstractNoninterruptibleWritableChannel.java
index fe998f3..6e4a05d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/AbstractNoninterruptibleWritableChannel.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/AbstractNoninterruptibleWritableChannel.java
@@ -39,6 +39,12 @@ abstract class AbstractNoninterruptibleWritableChannel implements WritableBuffer
     protected abstract void flushImpl() throws IOException;
 
     @Override
+    public final void flush() throws IOException
+    {
+        flushImpl();
+    }
+
+    @Override
     public final int write( ByteBuffer src ) throws IOException
     {
         return write( src, true );
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/WritableBufferedByteChannel.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/WritableBufferedByteChannel.java
index 42c0d08..cc8409c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/WritableBufferedByteChannel.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/WritableBufferedByteChannel.java
@@ -33,4 +33,6 @@ import java.nio.channels.WritableByteChannel;
 public interface WritableBufferedByteChannel extends WritableByteChannel
 {
     void writeBuffered( ByteBuffer src ) throws IOException;
+
+    void flush() throws IOException;
 }
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
index fa664be..5c5c34f 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterConstants.java
@@ -59,4 +59,5 @@ public final class BooterConstants
     public static final String PLUGIN_PID = "pluginPid";
     public static final String PROCESS_CHECKER = "processChecker";
     public static final String FORK_NODE_CONNECTION_STRING = "forkNodeConnectionString";
+    public static final String OUTPUT_FLUSH_INTERVAL_MS = "outputFlushInterval";
 }
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
index 4ec8cec..0df4ead 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -131,11 +131,13 @@ public class BooterDeserializer
         Integer systemExitTimeout =
                 systemExitTimeoutAsString == null ? null : Integer.valueOf( systemExitTimeoutAsString );
 
+        long outputFlushIntervalMs = properties.getLongProperty( OUTPUT_FLUSH_INTERVAL_MS );
+
         return new ProviderConfiguration( dirScannerParams, runOrderParameters,
                                           properties.getBooleanProperty( FAILIFNOTESTS ), reporterConfiguration, testNg,
                                           testSuiteDefinition, properties.getProperties(), typeEncodedTestForFork,
                                           preferTestsFromInStream, fromStrings( cli ), failFastCount, shutdown,
-                                          systemExitTimeout );
+                                          systemExitTimeout, outputFlushIntervalMs );
     }
 
     public StartupConfiguration getStartupConfiguration()
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 d8e3bfe..cd27162 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
@@ -27,6 +27,9 @@ import org.apache.maven.surefire.api.booter.ForkingReporterFactory;
 import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
 import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
 import org.apache.maven.surefire.api.booter.Shutdown;
+import org.apache.maven.surefire.api.util.internal.DaemonThreadFactory;
+import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
+import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
 import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelProcessorFactory;
 import org.apache.maven.surefire.booter.spi.SurefireMasterProcessChannelProcessorFactory;
 import org.apache.maven.surefire.api.provider.CommandListener;
@@ -50,6 +53,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.security.AccessControlException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.Semaphore;
@@ -100,6 +104,7 @@ public final class ForkedBooter
     private ForkingReporterFactory forkingReporterFactory;
     private StartupConfiguration startupConfiguration;
     private Object testSet;
+    private ScheduledExecutorService flusher;
 
     private void setupBooter( String tmpDir, String dumpFileName, String surefirePropsFileName,
                               String effectiveSystemPropertiesFileName )
@@ -129,6 +134,34 @@ public final class ForkedBooter
 
         flushEventChannelOnExit();
 
+        final Long outputFlushInterval = providerConfiguration.getOutputFlushInterval();
+        if ( outputFlushInterval != null && outputFlushInterval > 0
+            && LegacyMasterProcessChannelEncoder.class.isInstance( eventChannel ) )
+        {
+            final LegacyMasterProcessChannelEncoder enc = LegacyMasterProcessChannelEncoder.class.cast( eventChannel );
+            flusher = Executors.newSingleThreadScheduledExecutor( DaemonThreadFactory.newDaemonThreadFactory() );
+            flusher.scheduleAtFixedRate( new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    final WritableBufferedByteChannel c = WritableBufferedByteChannel.class.cast( enc.getOut() );
+                    try
+                    {
+                        if ( c.isOpen() )
+                        {
+                            c.flush();
+                        }
+
+                    }
+                    catch ( Exception e )
+                    {
+                        // no-op, not important, we tried anyway
+                    }
+                }
+            }, outputFlushInterval, outputFlushInterval, MILLISECONDS );
+        }
+
         forkingReporterFactory = createForkingReporterFactory();
         ConsoleLogger logger = (ConsoleLogger) forkingReporterFactory.createReporter();
         commandReader = new CommandReader( decoder, providerConfiguration.getShutdown(), logger );
@@ -237,6 +270,18 @@ public final class ForkedBooter
                 e.printStackTrace();
             }
         }
+        if ( flusher != null )
+        {
+            flusher.shutdownNow();
+            try
+            { // give a chance to finish sync, not that important if it fails
+                flusher.awaitTermination( 2, SECONDS );
+            }
+            catch ( InterruptedException e )
+            {
+                Thread.currentThread().interrupt();
+            }
+        }
     }
 
     private PingScheduler listenToShutdownCommands( String ppid, ConsoleLogger logger )
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
index 54b6187..77519c2 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProviderConfiguration.java
@@ -68,6 +68,8 @@ public class ProviderConfiguration
 
     private final Integer systemExitTimeout;
 
+    private final Long outputFlushInterval;
+
     @SuppressWarnings( "checkstyle:parameternumber" )
     public ProviderConfiguration( DirectoryScannerParameters directoryScannerParameters,
                                   RunOrderParameters runOrderParameters, boolean failIfNoTests,
@@ -75,7 +77,7 @@ public class ProviderConfiguration
                                   TestRequest testSuiteDefinition, Map<String, String> providerProperties,
                                   TypeEncodedValue typeEncodedTestSet, boolean readTestsFromInStream,
                                   List<CommandLineOption> mainCliOptions, int skipAfterFailureCount,
-                                  Shutdown shutdown, Integer systemExitTimeout )
+                                  Shutdown shutdown, Integer systemExitTimeout, Long outputFlushInterval )
     {
         this.runOrderParameters = runOrderParameters;
         this.providerProperties = providerProperties;
@@ -90,6 +92,12 @@ public class ProviderConfiguration
         this.skipAfterFailureCount = skipAfterFailureCount;
         this.shutdown = shutdown;
         this.systemExitTimeout = systemExitTimeout;
+        this.outputFlushInterval = outputFlushInterval;
+    }
+
+    public Long getOutputFlushInterval()
+    {
+        return outputFlushInterval;
     }
 
     public ReporterConfiguration getReporterConfiguration()
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
index 3cbc8eb..4c6d494 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
@@ -275,6 +275,11 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
         error( stackTraceWriter, trimStackTraces, BOOTERCODE_JVM_EXIT_ERROR, true );
     }
 
+    public WritableBufferedByteChannel getOut()
+    {
+        return out;
+    }
+
     private void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces, ForkedProcessEventType event,
                         @SuppressWarnings( "SameParameterValue" ) boolean sendImmediately )
     {