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 2020/07/09 15:34:53 UTC

[maven-surefire] 02/02: simple flush proposal

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

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

commit f72e7cfb67f8aa50357e6a21f81e83b4c8651859
Author: tibordigana <ti...@apache.org>
AuthorDate: Wed Jul 8 15:37:07 2020 +0200

    simple flush proposal
---
 .../AbstractNoninterruptibleWritableChannel.java   | 15 ++----
 .../util/internal/WritableBufferedByteChannel.java |  1 +
 .../api/util/internal/ChannelsWriterTest.java      | 47 ++++++++++++++++--
 ...tractMasterProcessChannelProcessorFactory.java} | 55 +++++-----------------
 ...LegacyMasterProcessChannelProcessorFactory.java | 41 ++--------------
 ...refireMasterProcessChannelProcessorFactory.java | 10 ++--
 6 files changed, 72 insertions(+), 97 deletions(-)

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..c2641e5 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
@@ -67,17 +67,12 @@ abstract class AbstractNoninterruptibleWritableChannel implements WritableBuffer
             src.flip();
         }
 
-        int countWrittenBytes = 0;
-
-        if ( src.hasRemaining() )
+        int countWrittenBytes = src.remaining();
+        writeImpl( src );
+        src.position( src.limit() );
+        if ( flush )
         {
-            countWrittenBytes = src.remaining();
-            writeImpl( src );
-            src.position( src.limit() );
-            if ( flush )
-            {
-                flushImpl();
-            }
+            flushImpl();
         }
         return countWrittenBytes;
     }
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..973424a 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
@@ -29,6 +29,7 @@ import java.nio.channels.WritableByteChannel;
  * and the channel is flushed after the buffer has overflew.
  * <br>
  * The method {@link #write(ByteBuffer)} flushes every written message.
+ * You can flush the channel by {@link #write(ByteBuffer) writing} the zero length of {@link ByteBuffer}.
  */
 public interface WritableBufferedByteChannel extends WritableByteChannel
 {
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/api/util/internal/ChannelsWriterTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/api/util/internal/ChannelsWriterTest.java
index 4befc24..24a09f3 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/api/util/internal/ChannelsWriterTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/api/util/internal/ChannelsWriterTest.java
@@ -137,6 +137,48 @@ public class ChannelsWriterTest
     }
 
     @Test
+    public void shouldFlushWhenEmptyBuffer() throws Exception
+    {
+        final boolean[] flushed = {false};
+        ByteArrayOutputStream out = new ByteArrayOutputStream()
+        {
+            @Override
+            public void flush() throws IOException
+            {
+                flushed[0] = true;
+                super.flush();
+            }
+        };
+        WritableByteChannel channel = Channels.newChannel( out );
+        ByteBuffer bb = ByteBuffer.allocate( 0 );
+        int countWritten = channel.write( bb );
+        assertThat( countWritten )
+            .isEqualTo( 0 );
+        assertThat( flushed[0] )
+            .isTrue();
+    }
+
+    @Test
+    public void shouldFlushWhenEmptyBufferOnBufferedWrites() throws Exception
+    {
+        final boolean[] flushed = {false};
+        ByteArrayOutputStream out = new ByteArrayOutputStream()
+        {
+            @Override
+            public void flush() throws IOException
+            {
+                flushed[0] = true;
+                super.flush();
+            }
+        };
+        WritableBufferedByteChannel channel = Channels.newBufferedChannel( out );
+        ByteBuffer bb = ByteBuffer.allocate( 0 );
+        channel.writeBuffered( bb );
+        assertThat( flushed[0] )
+            .isFalse();
+    }
+
+    @Test
     public void bufferedChannel() throws Exception
     {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -151,11 +193,6 @@ public class ChannelsWriterTest
         assertThat( out.toByteArray() )
             .isEmpty();
 
-        channel.write( ByteBuffer.allocate( 0 ) );
-
-        assertThat( out.toByteArray() )
-            .isEmpty();
-
         channel.write( ByteBuffer.wrap( new byte[] {4} ) );
 
         assertThat( out.toByteArray() )
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/AbstractMasterProcessChannelProcessorFactory.java
similarity index 54%
copy from surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java
copy to surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/AbstractMasterProcessChannelProcessorFactory.java
index e7eb3db..b390bf0 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/AbstractMasterProcessChannelProcessorFactory.java
@@ -19,63 +19,32 @@ package org.apache.maven.surefire.booter.spi;
  * under the License.
  */
 
-import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
-import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
 import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
 
 import java.io.IOException;
-import java.net.MalformedURLException;
 import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
 import java.util.concurrent.ScheduledExecutorService;
 
 import static java.util.concurrent.Executors.newScheduledThreadPool;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
 import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
 
 /**
- * Producer of encoder and decoder for process pipes.
- * <br>
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M5
+ * Default implementation of {@link MasterProcessChannelProcessorFactory}.
  */
-public class LegacyMasterProcessChannelProcessorFactory
+public abstract class AbstractMasterProcessChannelProcessorFactory
     implements MasterProcessChannelProcessorFactory
 {
     private final ScheduledExecutorService flusher;
 
-    public LegacyMasterProcessChannelProcessorFactory()
+    public AbstractMasterProcessChannelProcessorFactory()
     {
         flusher = newScheduledThreadPool( 1, newDaemonThreadFactory() );
     }
 
-    @Override
-    public boolean canUse( String channelConfig )
-    {
-        return channelConfig.startsWith( "pipe://" );
-    }
-
-    @Override
-    public void connect( String channelConfig ) throws IOException
-    {
-        if ( !canUse( channelConfig ) )
-        {
-            throw new MalformedURLException( "Unknown chanel string " + channelConfig );
-        }
-    }
-
-    @Override
-    public MasterProcessChannelDecoder createDecoder()
-    {
-        return new LegacyMasterProcessChannelDecoder( newBufferedChannel( System.in ) );
-    }
-
-    @Override
-    public MasterProcessChannelEncoder createEncoder()
+    protected void schedulePeriodicFlusher( int delayInMillis, final WritableByteChannel channel  )
     {
-        final WritableBufferedByteChannel channel = newBufferedChannel( System.out );
         flusher.scheduleWithFixedDelay( new Runnable()
         {
             @Override
@@ -83,21 +52,23 @@ public class LegacyMasterProcessChannelProcessorFactory
             {
                 try
                 {
-                    channel.write( ByteBuffer.wrap( new byte[] {'\n'} ) );
+                    channel.write( ByteBuffer.allocate( 0 ) );
                 }
-                catch ( IOException e )
+                catch ( Exception e )
                 {
                     // cannot do anything about this I/O issue
                 }
             }
-        }, 0L, 100, MILLISECONDS );
-
-        return new LegacyMasterProcessChannelEncoder( channel );
+        }, 0L, delayInMillis, MILLISECONDS );
     }
 
     @Override
-    public void close()
+    public void close() throws IOException
     {
         flusher.shutdown();
+        // Do NOT call awaitTermination() due to this would unnecessarily prolong teardown time of the JVM.
+        // It is not a critical situation when the JXM exits this daemon thread because the interrupted
+        // flusher does not break any business function. All business data is already safely flushed by test events,
+        // then by sending BYE event at the exit time and finally by flushEventChannelOnExit() in ForkedBooter.
     }
 }
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java
index e7eb3db..bef079d 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelProcessorFactory.java
@@ -22,17 +22,11 @@ package org.apache.maven.surefire.booter.spi;
 import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
 import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
 import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
-import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.ScheduledExecutorService;
 
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
-import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
 
 /**
  * Producer of encoder and decoder for process pipes.
@@ -42,15 +36,8 @@ import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.ne
  * @since 3.0.0-M5
  */
 public class LegacyMasterProcessChannelProcessorFactory
-    implements MasterProcessChannelProcessorFactory
+    extends AbstractMasterProcessChannelProcessorFactory
 {
-    private final ScheduledExecutorService flusher;
-
-    public LegacyMasterProcessChannelProcessorFactory()
-    {
-        flusher = newScheduledThreadPool( 1, newDaemonThreadFactory() );
-    }
-
     @Override
     public boolean canUse( String channelConfig )
     {
@@ -73,31 +60,11 @@ public class LegacyMasterProcessChannelProcessorFactory
     }
 
     @Override
+    @SuppressWarnings( "checkstyle:magicnumber" )
     public MasterProcessChannelEncoder createEncoder()
     {
-        final WritableBufferedByteChannel channel = newBufferedChannel( System.out );
-        flusher.scheduleWithFixedDelay( new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    channel.write( ByteBuffer.wrap( new byte[] {'\n'} ) );
-                }
-                catch ( IOException e )
-                {
-                    // cannot do anything about this I/O issue
-                }
-            }
-        }, 0L, 100, MILLISECONDS );
-
+        WritableBufferedByteChannel channel = newBufferedChannel( System.out );
+        schedulePeriodicFlusher( 200, channel );
         return new LegacyMasterProcessChannelEncoder( channel );
     }
-
-    @Override
-    public void close()
-    {
-        flusher.shutdown();
-    }
 }
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/SurefireMasterProcessChannelProcessorFactory.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/SurefireMasterProcessChannelProcessorFactory.java
index 9efff25..9b4e6c1 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/SurefireMasterProcessChannelProcessorFactory.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/SurefireMasterProcessChannelProcessorFactory.java
@@ -21,7 +21,7 @@ package org.apache.maven.surefire.booter.spi;
 
 import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
 import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
-import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
+import org.apache.maven.surefire.api.util.internal.WritableBufferedByteChannel;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -53,7 +53,7 @@ import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.ne
  * @since 3.0.0-M5
  */
 public class SurefireMasterProcessChannelProcessorFactory
-    implements MasterProcessChannelProcessorFactory
+    extends AbstractMasterProcessChannelProcessorFactory
 {
     private volatile AsynchronousSocketChannel clientSocketChannel;
 
@@ -102,14 +102,18 @@ public class SurefireMasterProcessChannelProcessorFactory
     }
 
     @Override
+    @SuppressWarnings( "checkstyle:magicnumber" )
     public MasterProcessChannelEncoder createEncoder()
     {
-        return new LegacyMasterProcessChannelEncoder( newBufferedChannel( newOutputStream( clientSocketChannel ) ) );
+        WritableBufferedByteChannel channel = newBufferedChannel( newOutputStream( clientSocketChannel ) );
+        schedulePeriodicFlusher( 200, channel );
+        return new LegacyMasterProcessChannelEncoder( channel );
     }
 
     @Override
     public void close() throws IOException
     {
+        super.close();
         if ( clientSocketChannel != null && clientSocketChannel.isOpen() )
         {
             clientSocketChannel.close();