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:51 UTC

[maven-surefire] branch flush updated (50bc56d -> f72e7cf)

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

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


    from 50bc56d  simple flush proposal
     new cdff5bd  Added tests with JPMS and resources in Surefire1733JUnitIT
     new f72e7cf  simple flush proposal

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:
 .../AbstractNoninterruptibleWritableChannel.java   | 15 ++---
 .../util/internal/WritableBufferedByteChannel.java |  1 +
 .../api/util/internal/ChannelsWriterTest.java      | 47 +++++++++++++--
 ...tractMasterProcessChannelProcessorFactory.java} | 55 ++++-------------
 ...LegacyMasterProcessChannelProcessorFactory.java | 41 ++-----------
 ...refireMasterProcessChannelProcessorFactory.java | 10 +++-
 .../surefire/its/jiras/Surefire1733JUnitIT.java    |  4 +-
 .../src/main/java/main/Service.java                | 18 ++++++
 .../src/main/java/module-info.java                 |  4 +-
 .../src/main/resources/main/a.txt                  |  1 +
 .../src/test/java/test/MyIT.java                   | 70 +++++++++++++++++++++-
 .../src/test/java/test/MyTest.java                 | 70 +++++++++++++++++++++-
 .../src/test/resources/tests/a.txt                 |  1 +
 13 files changed, 235 insertions(+), 102 deletions(-)
 copy surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/{LegacyMasterProcessChannelProcessorFactory.java => AbstractMasterProcessChannelProcessorFactory.java} (54%)
 create mode 100644 surefire-its/src/test/resources/surefire-1733-junit4/src/main/resources/main/a.txt
 create mode 100644 surefire-its/src/test/resources/surefire-1733-junit4/src/test/resources/tests/a.txt


[maven-surefire] 01/02: Added tests with JPMS and resources in Surefire1733JUnitIT

Posted by ti...@apache.org.
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 cdff5bd6971dbcf1bb6e0277b39d27549fa184e2
Author: tibordigana <ti...@apache.org>
AuthorDate: Sun Jun 28 03:33:25 2020 +0200

    Added tests with JPMS and resources in Surefire1733JUnitIT
---
 .../surefire/its/jiras/Surefire1733JUnitIT.java    |  4 +-
 .../src/main/java/main/Service.java                | 18 ++++++
 .../src/main/java/module-info.java                 |  4 +-
 .../src/main/resources/main/a.txt                  |  1 +
 .../src/test/java/test/MyIT.java                   | 70 +++++++++++++++++++++-
 .../src/test/java/test/MyTest.java                 | 70 +++++++++++++++++++++-
 .../src/test/resources/tests/a.txt                 |  1 +
 7 files changed, 163 insertions(+), 5 deletions(-)

diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1733JUnitIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1733JUnitIT.java
index 242fede..fe45d68 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1733JUnitIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1733JUnitIT.java
@@ -42,7 +42,9 @@ public class Surefire1733JUnitIT extends AbstractJigsawIT
             .assertThatLogLine( containsString( "Running test.MyIT" ), is( 1 ) )
             .assertThatLogLine( containsString( "class main.Service in the module \"main\"" ), is( 2 ) )
             .assertThatLogLine( containsString( "class test.MyTest in the module \"test\"" ), is( 1 ) )
-            .assertThatLogLine( containsString( "class test.MyIT in the module \"test\"" ), is( 1 ) );
+            .assertThatLogLine( containsString( "class test.MyIT in the module \"test\"" ), is( 1 ) )
+            .assertThatLogLine( containsString( "Hi there!" ), is( 4 ) )
+            .assertThatLogLine( containsString( "Hello!" ), is( 4 ) );
     }
 
     @Override
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/main/Service.java b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/main/Service.java
index 68592db..03e8340 100644
--- a/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/main/Service.java
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/main/Service.java
@@ -19,9 +19,27 @@ package main;
  * under the License.
  */
 
+import java.io.IOException;
+import java.util.Scanner;
+
 /**
  *
  */
 public class Service
 {
+    public String getNormalResource()
+    {
+        try ( Scanner scanner = new Scanner( getClass().getResourceAsStream( "/main/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    public String getResourceByJPMS() throws IOException
+    {
+        try ( Scanner scanner = new Scanner( getClass().getModule().getResourceAsStream( "main/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
 }
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/module-info.java b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/module-info.java
index 216ec8a..7eadcb4 100644
--- a/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/module-info.java
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/java/module-info.java
@@ -18,9 +18,9 @@
  */
 
 /**
- *
+ * "open" for testing Class.getResourceAsStream(), a resource in main module called by test module.
  */
-module main
+open module main
 {
     exports main;
 }
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/main/resources/main/a.txt b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/resources/main/a.txt
new file mode 100644
index 0000000..26bdedc
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/main/resources/main/a.txt
@@ -0,0 +1 @@
+Hi there!
\ No newline at end of file
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyIT.java b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyIT.java
index 3e3eb52..c36a356 100644
--- a/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyIT.java
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyIT.java
@@ -22,6 +22,9 @@ package test;
 import main.Service;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.util.Scanner;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
@@ -31,7 +34,7 @@ import static org.hamcrest.Matchers.is;
 public class MyIT
 {
     @Test
-    public void test()
+    public void test() throws Exception
     {
         Service service = new Service();
         String moduleName = service.getClass().getModule().getName();
@@ -41,5 +44,70 @@ public class MyIT
         moduleName = getClass().getModule().getName();
         System.out.println( getClass() + " in the module \"" + moduleName + "\"" );
         assertThat( moduleName, is( "test" ) );
+
+        System.out.println( service.getNormalResource() );
+        assertThat( service.getNormalResource(), is( "Hi there!" ) );
+
+        System.out.println( service.getResourceByJPMS() );
+        assertThat( service.getResourceByJPMS(), is( "Hi there!" ) );
+
+        System.out.println( getNormalResource() );
+        assertThat( getNormalResource(), is( "Hello!" ) );
+
+        System.out.println( getResourceByJPMS() );
+        assertThat( getResourceByJPMS(), is( "Hello!" ) );
+
+        Module main = ModuleLayer.boot()
+            .modules()
+            .stream()
+            .filter( m -> hasResource( m, "main/a.txt" ) )
+            .findFirst()
+            .get();
+        assertThat( getResourceByModule( main, "main/a.txt" ), is( "Hi there!" ) );
+        assertThat( getMainResource(), is( "Hi there!" ) );
+    }
+
+    private String getNormalResource()
+    {
+        try ( Scanner scanner = new Scanner( getClass().getResourceAsStream( "/tests/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getResourceByJPMS() throws IOException
+    {
+        try ( Scanner scanner = new Scanner( getClass().getModule().getResourceAsStream( "tests/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getResourceByModule( Module module, String resource ) throws IOException
+    {
+        try ( Scanner scanner = new Scanner( module.getResourceAsStream( resource ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getMainResource()
+    {
+        try ( Scanner scanner = new Scanner( Service.class.getResourceAsStream( "/main/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private static boolean hasResource( Module module, String resource )
+    {
+        try
+        {
+            return module.getResourceAsStream( resource ) != null;
+        }
+        catch ( IOException e )
+        {
+            return false;
+        }
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyTest.java b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyTest.java
index c839350..28c190d 100644
--- a/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyTest.java
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/java/test/MyTest.java
@@ -22,6 +22,9 @@ package test;
 import main.Service;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.util.Scanner;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
@@ -31,7 +34,7 @@ import static org.hamcrest.Matchers.is;
 public class MyTest
 {
     @Test
-    public void test()
+    public void test() throws Exception
     {
         Service service = new Service();
         String moduleName = service.getClass().getModule().getName();
@@ -41,5 +44,70 @@ public class MyTest
         moduleName = getClass().getModule().getName();
         System.out.println( getClass() + " in the module \"" + moduleName + "\"" );
         assertThat( moduleName, is( "test" ) );
+
+        System.out.println( service.getNormalResource() );
+        assertThat( service.getNormalResource(), is( "Hi there!" ) );
+
+        System.out.println( service.getResourceByJPMS() );
+        assertThat( service.getResourceByJPMS(), is( "Hi there!" ) );
+
+        System.out.println( getNormalResource() );
+        assertThat( getNormalResource(), is( "Hello!" ) );
+
+        System.out.println( getResourceByJPMS() );
+        assertThat( getResourceByJPMS(), is( "Hello!" ) );
+
+        Module main = ModuleLayer.boot()
+            .modules()
+            .stream()
+            .filter( m -> hasResource( m, "main/a.txt" ) )
+            .findFirst()
+            .get();
+        assertThat( getResourceByModule( main, "main/a.txt" ), is( "Hi there!" ) );
+        assertThat( getMainResource(), is( "Hi there!" ) );
+    }
+
+    private String getNormalResource()
+    {
+        try ( Scanner scanner = new Scanner( getClass().getResourceAsStream( "/tests/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getResourceByJPMS() throws IOException
+    {
+        try ( Scanner scanner = new Scanner( getClass().getModule().getResourceAsStream( "tests/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getResourceByModule( Module module, String resource ) throws IOException
+    {
+        try ( Scanner scanner = new Scanner( module.getResourceAsStream( resource ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private String getMainResource()
+    {
+        try ( Scanner scanner = new Scanner( Service.class.getResourceAsStream( "/main/a.txt" ) ) )
+        {
+            return scanner.nextLine();
+        }
+    }
+
+    private static boolean hasResource( Module module, String resource )
+    {
+        try
+        {
+            return module.getResourceAsStream( resource ) != null;
+        }
+        catch ( IOException e )
+        {
+            return false;
+        }
     }
 }
diff --git a/surefire-its/src/test/resources/surefire-1733-junit4/src/test/resources/tests/a.txt b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/resources/tests/a.txt
new file mode 100644
index 0000000..05a682b
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-1733-junit4/src/test/resources/tests/a.txt
@@ -0,0 +1 @@
+Hello!
\ No newline at end of file


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

Posted by ti...@apache.org.
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();