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:50 UTC
[maven-surefire] 01/01: enable to flush regularly output of the
forked process
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 )
{