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/04/03 09:21:04 UTC
[maven-surefire] branch maven2surefire-jvm-communication updated:
fixed performance problem in TCP/Pipes communication (we do NOT flush every
time, used buffered channels,
used Async Sockets instead of blocking NIO Sockets)
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch maven2surefire-jvm-communication
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/maven2surefire-jvm-communication by this push:
new 979034c fixed performance problem in TCP/Pipes communication (we do NOT flush every time, used buffered channels, used Async Sockets instead of blocking NIO Sockets)
979034c is described below
commit 979034c18feaab4e71e786de0fed7e19ca360ced
Author: tibordigana <ti...@apache.org>
AuthorDate: Fri Apr 3 11:20:50 2020 +0200
fixed performance problem in TCP/Pipes communication (we do NOT flush every time, used buffered channels, used Async Sockets instead of blocking NIO Sockets)
---
.../surefire/booterclient/output/ForkClient.java | 13 +-
.../surefire/extensions/EventConsumerThread.java | 4 +-
.../surefire/extensions/SurefireForkChannel.java | 60 ++++--
.../booterclient/ForkingRunListenerTest.java | 12 +-
.../TestLessInputStreamBuilderTest.java | 2 +-
.../TestProvidingInputStreamTest.java | 2 +-
.../booterclient/output/ForkClientTest.java | 2 +-
.../surefire/extensions/AsyncSocketTest.java | 228 +++++++++++++++++++++
.../maven/plugin/surefire/extensions/E2ETest.java | 105 +++++++---
.../extensions/ForkedProcessEventNotifierTest.java | 76 ++++---
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 4 +
.../maven/surefire/extensions/ForkChannelTest.java | 33 ++-
.../maven/surefire/booter/BaseProviderFactory.java | 7 -
.../surefire/booter/ForkingReporterFactory.java | 1 -
.../maven/surefire/booter/ForkingRunListener.java | 1 -
.../MasterProcessChannelDecoder.java | 4 +-
.../MasterProcessChannelEncoder.java | 4 +-
.../surefire/providerapi/ProviderParameters.java | 2 -
.../AbstractNoninterruptibleWritableChannel.java | 28 +--
.../maven/surefire/util/internal/Channels.java | 188 ++++++++++++++---
.../util/internal/WritableBufferedByteChannel.java | 36 ++++
.../surefire/booter/ForkingRunListenerTest.java | 1 -
.../surefire/util/internal/ChannelsReaderTest.java | 58 +++++-
.../surefire/util/internal/ChannelsWriterTest.java | 43 +++-
.../maven/surefire/booter/CommandReader.java | 2 -
.../apache/maven/surefire/booter/ForkedBooter.java | 25 ++-
.../maven/surefire/booter/LazyTestsToRun.java | 1 -
.../spi/LegacyMasterProcessChannelDecoder.java | 2 +-
.../spi/LegacyMasterProcessChannelEncoder.java | 98 +++++----
...LegacyMasterProcessChannelProcessorFactory.java | 11 +-
...refireMasterProcessChannelProcessorFactory.java | 52 ++++-
.../maven/surefire/booter/CommandReaderTest.java | 10 +-
.../surefire/booter/ForkedBooterMockTest.java | 2 -
.../maven/surefire/booter/ForkedBooterTest.java | 3 +-
.../spi/LegacyMasterProcessChannelEncoderTest.java | 77 ++++---
.../extensions/util/CommandlineStreams.java | 9 +-
.../spi/MasterProcessChannelProcessorFactory.java | 4 +-
.../apache/maven/surefire/its/ConsoleOutputIT.java | 19 +-
.../src/test/java/consoleOutput/Test1.java | 20 +-
.../src/test/java/consoleoutput_noisy/Test3.java | 52 +++++
40 files changed, 995 insertions(+), 306 deletions(-)
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 b4de014..bc76dfe 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
@@ -24,7 +24,7 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.surefire.eventapi.Event;
import org.apache.maven.surefire.extensions.EventHandler;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
@@ -111,6 +111,7 @@ public class ForkClient
notifier.setStopOnNextTestListener( new StopOnNextTestListener() );
notifier.setConsoleDebugListener( new DebugListener() );
notifier.setConsoleWarningListener( new WarningListener() );
+ notifier.setExitErrorEventListener( new ExitErrorEventListener() );
}
private final class TestSetStartingListener
@@ -303,6 +304,16 @@ public class ForkClient
}
}
+ private final class ExitErrorEventListener implements ForkedProcessExitErrorListener
+ {
+ @Override
+ public void handle( StackTraceWriter stackTrace )
+ {
+ getOrCreateConsoleLogger()
+ .error( "System Exit has timed out in the forked process " + forkNumber );
+ }
+ }
+
/**
* Overridden by a subclass, see {@link org.apache.maven.plugin.surefire.booterclient.ForkStarter}.
*/
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
index b92a238..8b8e2f3 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
@@ -19,7 +19,6 @@ package org.apache.maven.plugin.surefire.extensions;
* under the License.
*/
-import org.apache.commons.codec.binary.Base64;
import org.apache.maven.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.booter.ForkedProcessEventType;
@@ -51,6 +50,7 @@ import org.apache.maven.surefire.extensions.util.CountdownCloseable;
import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.report.TestSetReportEntry;
+import org.apache.maven.surefire.shared.codec.binary.Base64;
import javax.annotation.Nonnull;
import java.io.IOException;
@@ -203,7 +203,7 @@ public class EventConsumerThread extends CloseableDaemonThread
private boolean read( ByteBuffer buffer ) throws IOException
{
- if ( buffer.hasRemaining() )
+ if ( buffer.hasRemaining() && buffer.position() > 0 )
{
return true;
}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
index 3285486..93607fb 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
@@ -28,21 +28,30 @@ import org.apache.maven.surefire.extensions.ForkChannel;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
import javax.annotation.Nonnull;
+import java.io.Closeable;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketOption;
-import java.nio.channels.Channel;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import static java.net.StandardSocketOptions.SO_KEEPALIVE;
import static java.net.StandardSocketOptions.SO_REUSEADDR;
import static java.net.StandardSocketOptions.TCP_NODELAY;
-import static java.nio.channels.ServerSocketChannel.open;
+import static java.nio.channels.AsynchronousChannelGroup.withThreadPool;
+import static java.nio.channels.AsynchronousServerSocketChannel.open;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newInputStream;
+import static org.apache.maven.surefire.util.internal.Channels.newOutputStream;
+import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
/**
* The TCP/IP server accepting only one client connection. The forked JVM connects to the server using the
@@ -60,34 +69,52 @@ import static java.nio.channels.ServerSocketChannel.open;
*/
final class SurefireForkChannel extends ForkChannel
{
+ private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool( newDaemonThreadFactory() );
+
private final ConsoleLogger logger;
- private final ServerSocketChannel server;
+ private final AsynchronousServerSocketChannel server;
+ private final String localHost;
private final int localPort;
- private volatile SocketChannel channel;
+ private volatile AsynchronousSocketChannel worker;
SurefireForkChannel( int forkChannelId, @Nonnull ConsoleLogger logger ) throws IOException
{
super( forkChannelId );
this.logger = logger;
- server = open();
+ server = open( withThreadPool( THREAD_POOL ) );
setTrueOptions( SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE );
InetAddress ip = Inet4Address.getLoopbackAddress();
server.bind( new InetSocketAddress( ip, 0 ), 1 );
- localPort = ( (InetSocketAddress) server.getLocalAddress() ).getPort();
+ InetSocketAddress localAddress = (InetSocketAddress) server.getLocalAddress();
+ localHost = localAddress.getHostString();
+ localPort = localAddress.getPort();
}
@Override
public void connectToClient() throws IOException
{
- if ( channel != null )
+ if ( worker != null )
{
throw new IllegalStateException( "already accepted TCP client connection" );
}
- channel = server.accept();
+
+ try
+ {
+ worker = server.accept().get();
+ }
+ catch ( InterruptedException e )
+ {
+ throw new IOException( e.getLocalizedMessage(), e );
+ }
+ catch ( ExecutionException e )
+ {
+ throw new IOException( e.getLocalizedMessage(), e.getCause() );
+ }
}
@SafeVarargs
- private final void setTrueOptions( SocketOption<Boolean>... options ) throws IOException
+ private final void setTrueOptions( SocketOption<Boolean>... options )
+ throws IOException
{
for ( SocketOption<Boolean> option : options )
{
@@ -101,7 +128,7 @@ final class SurefireForkChannel extends ForkChannel
@Override
public String getForkNodeConnectionString()
{
- return "tcp://127.0.0.1:" + localPort;
+ return "tcp://" + localHost + ":" + localPort;
}
@Override
@@ -114,6 +141,10 @@ final class SurefireForkChannel extends ForkChannel
public CloseableDaemonThread bindCommandReader( @Nonnull CommandReader commands,
WritableByteChannel stdIn )
{
+ // dont use newBufferedChannel here - may cause the command is not sent and the JVM hangs
+ // only newChannel flushes the message
+ // newBufferedChannel does not flush
+ WritableByteChannel channel = newChannel( newOutputStream( worker ) );
return new StreamFeeder( "commands-fork-" + getForkChannelId(), channel, commands, logger );
}
@@ -122,6 +153,7 @@ final class SurefireForkChannel extends ForkChannel
@Nonnull CountdownCloseable countdownCloseable,
ReadableByteChannel stdOut )
{
+ ReadableByteChannel channel = newBufferedChannel( newInputStream( worker ) );
return new EventConsumerThread( "fork-" + getForkChannelId() + "-event-thread-", channel,
eventHandler, countdownCloseable, logger );
}
@@ -129,8 +161,8 @@ final class SurefireForkChannel extends ForkChannel
@Override
public void close() throws IOException
{
- //noinspection EmptyTryBlock
- try ( Channel c1 = channel; Channel c2 = server )
+ //noinspection unused,EmptyTryBlock,EmptyTryBlock
+ try ( Closeable c1 = worker; Closeable c2 = server )
{
// only close all channels
}
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 4ca19ad..8aeba39 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
@@ -38,6 +38,7 @@ import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.report.TestSetReportEntry;
+import org.apache.maven.surefire.util.internal.WritableBufferedByteChannel;
import javax.annotation.Nonnull;
import java.io.ByteArrayInputStream;
@@ -53,7 +54,8 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import static java.nio.channels.Channels.newChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newChannel;
import static org.mockito.Mockito.mock;
/**
@@ -243,10 +245,11 @@ public class ForkingRunListenerTest
ReportEntry expected = createDefaultReportEntry();
SimpleReportEntry secondExpected = createAnotherDefaultReportEntry();
- new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( printStream ) ), false )
+ new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newBufferedChannel( printStream ) ), false )
.testStarting( expected );
- new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( anotherPrintStream ) ), false )
+ new ForkingRunListener(
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( anotherPrintStream ) ), false )
.testSkipped( secondExpected );
TestSetMockReporterFactory providerReporterFactory = new TestSetMockReporterFactory();
@@ -362,7 +365,8 @@ public class ForkingRunListenerTest
private RunListener createForkingRunListener()
{
- return new ForkingRunListener( new LegacyMasterProcessChannelEncoder( newChannel( printStream ) ), false );
+ WritableBufferedByteChannel channel = (WritableBufferedByteChannel) newChannel( printStream );
+ return new ForkingRunListener( new LegacyMasterProcessChannelEncoder( channel ), false );
}
private class StandardTestRun
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
index 2aab4c2..7c89492 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
@@ -22,7 +22,7 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.MasterProcessCommand;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
index 1d348ce..3e2023e 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
@@ -22,7 +22,7 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
import org.apache.maven.plugin.surefire.extensions.StreamFeeder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
import org.junit.Test;
import java.io.IOException;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
index 60f6872..453e735 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java
@@ -66,7 +66,7 @@ import java.util.concurrent.TimeUnit;
import static java.nio.channels.Channels.newChannel;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.codec.binary.Base64.encodeBase64String;
+import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_DEBUG;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_ERR;
import static org.apache.maven.plugin.surefire.booterclient.MockReporter.CONSOLE_INFO;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/AsyncSocketTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/AsyncSocketTest.java
new file mode 100644
index 0000000..88cba07
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/AsyncSocketTest.java
@@ -0,0 +1,228 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * 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.util.internal.DaemonThreadFactory;
+import org.junit.Test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketOption;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static java.net.StandardSocketOptions.SO_KEEPALIVE;
+import static java.net.StandardSocketOptions.SO_REUSEADDR;
+import static java.net.StandardSocketOptions.TCP_NODELAY;
+import static org.apache.maven.surefire.util.internal.Channels.newInputStream;
+import static org.apache.maven.surefire.util.internal.Channels.newOutputStream;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ *
+ */
+public class AsyncSocketTest
+{
+ private static final String LONG_STRING =
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
+
+ private final CountDownLatch barrier = new CountDownLatch( 1 );
+ private final AtomicLong writeTime = new AtomicLong();
+ private final AtomicLong readTime = new AtomicLong();
+
+ private volatile InetSocketAddress address;
+
+ @Test
+ public void test() throws Exception
+ {
+ int forks = 2;
+ ThreadFactory factory = DaemonThreadFactory.newDaemonThreadFactory();
+ ExecutorService executorService = Executors.newCachedThreadPool( factory );
+ if ( executorService instanceof ThreadPoolExecutor )
+ {
+ ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
+ threadPoolExecutor.setCorePoolSize( Math.min( forks, Runtime.getRuntime().availableProcessors() ) );
+ threadPoolExecutor.prestartCoreThread();
+ }
+ AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool( executorService );
+ AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open( group );
+ setTrueOptions( server, SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE );
+ server.bind( null, 1 );
+ address = (InetSocketAddress) server.getLocalAddress();
+
+ System.gc();
+ TimeUnit.SECONDS.sleep( 3L );
+
+ Thread tc = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ client();
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+ };
+ tc.setDaemon( true );
+ tc.start();
+
+ Future<AsynchronousSocketChannel> acceptFuture = server.accept();
+ AsynchronousSocketChannel worker = acceptFuture.get();
+ if ( !worker.isOpen() )
+ {
+ throw new IOException( "client socket closed" );
+ }
+ final InputStream is = newInputStream( worker );
+ final OutputStream os = new BufferedOutputStream( newOutputStream( worker ), 64 * 1024 );
+
+ Thread tt = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ byte[] b = new byte[1024];
+ is.read( b );
+ }
+ catch ( Exception e )
+ {
+ //e.printStackTrace();
+ }
+
+ }
+ };
+ tt.setName( "fork-1-event-thread-" );
+ tt.setDaemon( true );
+ tt.start();
+
+ Thread t = new Thread()
+ {
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ public void run()
+ {
+ try
+ {
+ byte[] data = LONG_STRING.getBytes( StandardCharsets.US_ASCII );
+ long t1 = System.currentTimeMillis();
+ int i = 0;
+ for ( ; i < 320_000; i++ )
+ {
+ os.write( data );
+ long t2 = System.currentTimeMillis();
+ long spent = t2 - t1;
+
+ if ( i % 100_000 == 0 )
+ {
+ System.out.println( spent + "ms: " + i );
+ }
+ }
+ os.flush();
+ long spent = System.currentTimeMillis() - t1;
+ writeTime.set( spent );
+ System.out.println( spent + "ms: " + i );
+ }
+ catch ( IOException e )
+ {
+ e.printStackTrace();
+ }
+
+ }
+ };
+ t.setName( "commands-fork-1" );
+ t.setDaemon( true );
+ t.start();
+
+ barrier.await();
+ tt.join();
+ t.join();
+ tc.join();
+ worker.close();
+ server.close();
+
+ // 160 millis on write using the asynchronous sockets
+ // 320 millis on NIO blocking sockets
+ assertThat( writeTime.get() )
+ .isLessThan( 1000L );
+
+ // 160 millis on read using the asynchronous sockets
+ // 320 millis on NIO blocking sockets
+ assertThat( readTime.get() )
+ .isLessThan( 1000L );
+ }
+
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ private void client() throws Exception
+ {
+ InetSocketAddress hostAddress = new InetSocketAddress( InetAddress.getLoopbackAddress(), address.getPort() );
+ AsynchronousSocketChannel clientSocketChannel = AsynchronousSocketChannel.open();
+ clientSocketChannel.connect( hostAddress ).get(); // Wait until connection is done.
+ InputStream is = new BufferedInputStream( newInputStream( clientSocketChannel ), 64 * 1024 );
+ List<byte[]> bytes = new ArrayList<>();
+ long t1 = System.currentTimeMillis();
+ for ( int i = 0; i < 320_000; i++ )
+ {
+ byte[] b = new byte[100];
+ is.read( b );
+ bytes.add( b );
+ }
+ long t2 = System.currentTimeMillis();
+ long spent = t2 - t1;
+ readTime.set( spent );
+ System.out.println( new String( bytes.get( bytes.size() - 1 ) ) );
+ System.out.println( "received within " + spent + "ms" );
+ clientSocketChannel.close();
+ barrier.countDown();
+ }
+
+ @SafeVarargs
+ private static void setTrueOptions( AsynchronousServerSocketChannel server, SocketOption<Boolean>... options )
+ throws IOException
+ {
+ for ( SocketOption<Boolean> option : options )
+ {
+ if ( server.supportedOptions().contains( option ) )
+ {
+ server.setOption( option, true );
+ }
+ }
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
index ec76a8c..c22da94 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/E2ETest.java
@@ -1,23 +1,47 @@
package org.apache.maven.plugin.surefire.extensions;
+/*
+ * 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.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.booter.spi.SurefireMasterProcessChannelProcessorFactory;
import org.apache.maven.surefire.eventapi.Event;
import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
-import org.apache.maven.surefire.report.ConsoleOutputCapture;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.junit.Test;
import javax.annotation.Nonnull;
import java.io.Closeable;
-import java.io.IOException;
-import java.io.PrintStream;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
+/**
+ * Simulates the End To End use case where Maven process and Surefire process communicate using the TCP/IP protocol.
+ */
+@SuppressWarnings( "checkstyle:magicnumber" )
public class E2ETest
{
private static final String LONG_STRING =
@@ -27,14 +51,20 @@ public class E2ETest
public void test() throws Exception
{
ConsoleLogger logger = mock( ConsoleLogger.class );
- SurefireForkChannel server = new SurefireForkChannel(1, logger );
+ final SurefireForkChannel server = new SurefireForkChannel( 1, logger );
final String connection = server.getForkNodeConnectionString();
- SurefireMasterProcessChannelProcessorFactory factory = new SurefireMasterProcessChannelProcessorFactory();
+ final SurefireMasterProcessChannelProcessorFactory factory = new SurefireMasterProcessChannelProcessorFactory();
factory.connect( connection );
final MasterProcessChannelEncoder encoder = factory.createEncoder();
+ System.gc();
+
+ TimeUnit.SECONDS.sleep( 3L );
+
+ final CountDownLatch awaitHandlerFinished = new CountDownLatch( 2 );
+
Thread t = new Thread()
{
@Override
@@ -49,20 +79,25 @@ public class E2ETest
}
};
- PrintStream out = System.out;
- PrintStream err = System.err;
+ //PrintStream out = System.out;
+ //PrintStream err = System.err;
- ConsoleOutputCapture.startCapture( target );
+ //ConsoleOutputCapture.startCapture( target );
try
{
- for ( int i = 0; i < 320_000; i++ )
+ long t1 = System.currentTimeMillis();
+ for ( int i = 0; i < 400_000; i++ )
{
- System.out.println( LONG_STRING );
+ //System.out.println( LONG_STRING );
+ encoder.stdOut( LONG_STRING, true );
}
- System.setOut( out );
- System.setErr( err );
- TimeUnit.MINUTES.sleep( 1L );
+ long t2 = System.currentTimeMillis();
+ long spent = t2 - t1;
+ //System.setOut( out );
+ //System.setErr( err );
+ System.out.println( spent + "ms on write" );
+ awaitHandlerFinished.countDown();
}
catch ( Exception e )
{
@@ -75,31 +110,39 @@ public class E2ETest
server.connectToClient();
+ final AtomicLong readTime = new AtomicLong();
+
EventHandler<Event> h = new EventHandler<Event>()
{
- volatile int i;
- volatile long t1;
+ private final AtomicInteger counter = new AtomicInteger();
+ private volatile long t1;
@Override
public void handleEvent( @Nonnull Event event )
{
try
{
- if ( i++ == 0 )
+ if ( counter.getAndIncrement() == 0 )
{
t1 = System.currentTimeMillis();
}
- if ( i == 320_000 )
+ long t2 = System.currentTimeMillis();
+ long spent = t2 - t1;
+
+ if ( counter.get() % 100_000 == 0 )
+ {
+ System.out.println( spent + "ms: " + counter.get() );
+ }
+
+ if ( counter.get() == 320_000 )
{
- long t2 = System.currentTimeMillis();
- TimeUnit.SECONDS.sleep( 1L );
- System.out.println( "Forked JVM spent "
- + ( t2 - t1 )
- + "ms on transferring all lines of the log." );
+ readTime.set( spent );
+ System.out.println( spent + "ms on read" );
+ awaitHandlerFinished.countDown();
}
}
- catch ( InterruptedException e )
+ catch ( Exception e )
{
e.printStackTrace();
}
@@ -109,18 +152,24 @@ public class E2ETest
Closeable c = new Closeable()
{
@Override
- public void close() throws IOException
+ public void close()
{
-
}
};
server.bindEventHandler( h, new CountdownCloseable( c, 1 ), null )
- .start();
+ .start();
- TimeUnit.SECONDS.sleep( 60L );
+ assertThat( awaitHandlerFinished.await( 30L, TimeUnit.SECONDS ) )
+ .isTrue();
factory.close();
server.close();
+
+ // 2 seconds while using the encoder/decoder
+ // 160 millis of sending pure data without encoder/decoder
+ assertThat( readTime.get() )
+ .isPositive()
+ .isLessThanOrEqualTo( 3_000L );
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
index cb2e382..369abe5 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java
@@ -39,6 +39,7 @@ import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.util.internal.ObjectUtils;
+import org.apache.maven.surefire.util.internal.WritableBufferedByteChannel;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
@@ -68,10 +69,11 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import static java.nio.channels.Channels.newChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newChannel;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.copyOfRange;
-import static org.apache.commons.codec.binary.Base64.encodeBase64String;
+import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertTrue;
@@ -114,9 +116,11 @@ public class ForkedProcessEventNotifierTest
public void shouldHaveSystemProperty() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
Map<String, String> props = ObjectUtils.systemProps();
encoder.sendSystemProperties( props );
+ wChannel.close();
ForkedProcessEventNotifier notifier = new ForkedProcessEventNotifier();
PropertyEventAssertionListener listener = new PropertyEventAssertionListener();
@@ -307,7 +311,8 @@ public class ForkedProcessEventNotifierTest
public void shouldSendByeEvent() throws Exception
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.bye();
String read = new String( out.toByteArray(), UTF_8 );
@@ -343,7 +348,8 @@ public class ForkedProcessEventNotifierTest
public void shouldSendStopOnNextTestEvent() throws Exception
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.stopOnNextTest();
String read = new String( out.toByteArray(), UTF_8 );
@@ -401,7 +407,8 @@ public class ForkedProcessEventNotifierTest
when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testFailed( reportEntry, true );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -427,7 +434,8 @@ public class ForkedProcessEventNotifierTest
public void shouldSendNextTestEvent() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.acquireNextTest();
String read = new String( out.toByteArray(), UTF_8 );
@@ -457,7 +465,8 @@ public class ForkedProcessEventNotifierTest
public void testConsole() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleInfoLog( "msg" );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -483,7 +492,8 @@ public class ForkedProcessEventNotifierTest
public void testError() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleErrorLog( "msg" );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -509,7 +519,8 @@ public class ForkedProcessEventNotifierTest
public void testErrorWithException() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
Throwable throwable = new Throwable( "msg" );
encoder.consoleErrorLog( throwable );
@@ -538,7 +549,8 @@ public class ForkedProcessEventNotifierTest
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "1", "2", "3" );
encoder.consoleErrorLog( stackTraceWriter, false );
@@ -566,7 +578,8 @@ public class ForkedProcessEventNotifierTest
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleDebugLog( "msg" );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -596,7 +609,8 @@ public class ForkedProcessEventNotifierTest
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleWarningLog( "msg" );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -622,8 +636,10 @@ public class ForkedProcessEventNotifierTest
public void testStdOutStream() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdOut( "msg", false );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -649,8 +665,10 @@ public class ForkedProcessEventNotifierTest
public void testStdOutStreamPrint() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdOut( "", false );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -676,8 +694,10 @@ public class ForkedProcessEventNotifierTest
public void testStdOutStreamPrintWithNull() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdOut( null, false );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -703,8 +723,10 @@ public class ForkedProcessEventNotifierTest
public void testStdOutStreamPrintln() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdOut( "", true );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -730,8 +752,10 @@ public class ForkedProcessEventNotifierTest
public void testStdOutStreamPrintlnWithNull() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdOut( null, true );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -757,8 +781,10 @@ public class ForkedProcessEventNotifierTest
public void testStdErrStream() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.stdErr( "msg", false );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -784,8 +810,10 @@ public class ForkedProcessEventNotifierTest
public void shouldCountSameNumberOfSystemProperties() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel wChannel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( wChannel );
encoder.sendSystemProperties( ObjectUtils.systemProps() );
+ wChannel.close();
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -839,14 +867,15 @@ public class ForkedProcessEventNotifierTest
public void shouldHandleExit() throws Exception
{
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
- encoder.sendExitEvent( stackTraceWriter, false );
+ encoder.sendExitError( stackTraceWriter, false );
ReadableByteChannel channel = newChannel( new ByteArrayInputStream( out.toByteArray() ) );
@@ -950,7 +979,8 @@ public class ForkedProcessEventNotifierTest
final Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder =
+ new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
LegacyMasterProcessChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
.invoke( encoder, reportEntry, trim );
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index a232544..94754a7 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -40,7 +40,9 @@ import org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfigu
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
+import org.apache.maven.plugin.surefire.extensions.AsyncSocketTest;
import org.apache.maven.plugin.surefire.extensions.ConsoleOutputReporterTest;
+import org.apache.maven.plugin.surefire.extensions.E2ETest;
import org.apache.maven.plugin.surefire.extensions.ForkedProcessEventNotifierTest;
import org.apache.maven.plugin.surefire.extensions.StatelessReporterTest;
import org.apache.maven.plugin.surefire.extensions.StreamFeederTest;
@@ -108,6 +110,8 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( ForkStarterTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkChannelTest.class ) );
suite.addTest( new JUnit4TestAdapter( StreamFeederTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( E2ETest.class ) );
+ suite.addTest( new JUnit4TestAdapter( AsyncSocketTest.class ) );
return suite;
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
index 68f2324..c3f6a8c 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/ForkChannelTest.java
@@ -35,10 +35,11 @@ import java.net.Socket;
import java.net.URI;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.util.concurrent.TimeUnit.SECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.fest.assertions.Assertions.assertThat;
/**
@@ -71,43 +72,35 @@ public class ForkChannelTest
assertThat( uri.getPort() )
.isPositive();
- Consumer consumer = new Consumer();
-
- Client client = new Client( uri.getPort() );
- client.start();
-
- channel.connectToClient();
- SECONDS.sleep( 3L );
-
- TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ final TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
TestLessInputStream commandReader = builder.build();
-
- channel.bindCommandReader( commandReader, null ).start();
-
- final AtomicBoolean isCloseableCalled = new AtomicBoolean();
+ final CountDownLatch isCloseableCalled = new CountDownLatch( 1 );
Closeable closeable = new Closeable()
{
@Override
public void close()
{
- isCloseableCalled.set( true );
+ isCloseableCalled.countDown();
}
};
CountdownCloseable cc = new CountdownCloseable( closeable, 1 );
- channel.bindEventHandler( consumer, cc, null ).start();
+ Consumer consumer = new Consumer();
- SECONDS.sleep( 3L );
+ Client client = new Client( uri.getPort() );
+ client.start();
- commandReader.noop();
+ channel.connectToClient();
+ channel.bindCommandReader( commandReader, null ).start();
+ channel.bindEventHandler( consumer, cc, null ).start();
- SECONDS.sleep( 3L );
+ commandReader.noop();
client.join( TESTCASE_TIMEOUT );
assertThat( hasError.get() )
.isFalse();
- assertThat( isCloseableCalled.get() )
+ assertThat( isCloseableCalled.await( TESTCASE_TIMEOUT, MILLISECONDS ) )
.isTrue();
assertThat( consumer.lines )
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
index 6ac0ce2..9ae9fbd 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
@@ -21,7 +21,6 @@ package org.apache.maven.surefire.booter;
import org.apache.maven.surefire.cli.CommandLineOption;
import org.apache.maven.surefire.providerapi.CommandChainReader;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.DefaultDirectConsoleReporter;
@@ -263,12 +262,6 @@ public class BaseProviderFactory
this.systemExitTimeout = systemExitTimeout;
}
- @Override
- public MasterProcessChannelEncoder getForkedChannelEncoder()
- {
- return masterProcessChannelEncoder;
- }
-
public void setForkedChannelEncoder( MasterProcessChannelEncoder masterProcessChannelEncoder )
{
this.masterProcessChannelEncoder = masterProcessChannelEncoder;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
index 1c6db50..c08b52e 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.suite.RunResult;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index 6148149..2603e8f 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReportEntry;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelDecoder.java
similarity index 94%
rename from surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelDecoder.java
index 4dc4908..dd06590 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelDecoder.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.providerapi;
+package org.apache.maven.surefire.booter;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,8 +19,6 @@ package org.apache.maven.surefire.providerapi;
* under the License.
*/
-import org.apache.maven.surefire.booter.Command;
-
import javax.annotation.Nonnull;
import java.io.IOException;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelEncoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
similarity index 95%
rename from surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelEncoder.java
rename to surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
index b734b61..062a57c 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelEncoder.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessChannelEncoder.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.providerapi;
+package org.apache.maven.surefire.booter;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -80,5 +80,5 @@ public interface MasterProcessChannelEncoder
void acquireNextTest();
- void sendExitEvent( StackTraceWriter stackTraceWriter, boolean trimStackTraces );
+ void sendExitError( StackTraceWriter stackTraceWriter, boolean trimStackTraces );
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
index 47a6a7e..f620cbf 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/ProviderParameters.java
@@ -147,7 +147,5 @@ public interface ProviderParameters
Integer getSystemExitTimeout();
- MasterProcessChannelEncoder getForkedChannelEncoder();
-
CommandChainReader getCommandReader();
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/AbstractNoninterruptibleWritableChannel.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/AbstractNoninterruptibleWritableChannel.java
index cb08e34..4c60bce 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/AbstractNoninterruptibleWritableChannel.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/AbstractNoninterruptibleWritableChannel.java
@@ -19,12 +19,10 @@ package org.apache.maven.surefire.util.internal;
* under the License.
*/
-import java.io.Flushable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NonWritableChannelException;
-import java.nio.channels.WritableByteChannel;
/**
* The channel used for writes which cannot be implicitly closed after the operational Thread
@@ -32,21 +30,27 @@ import java.nio.channels.WritableByteChannel;
*
* @since 3.0.0-M5
*/
-abstract class AbstractNoninterruptibleWritableChannel implements WritableByteChannel, Flushable
+abstract class AbstractNoninterruptibleWritableChannel implements WritableBufferedByteChannel
{
- private final boolean flushable;
private volatile boolean open = true;
- AbstractNoninterruptibleWritableChannel( boolean flushable )
- {
- this.flushable = flushable;
- }
-
protected abstract void writeImpl( ByteBuffer src ) throws IOException;
protected abstract void closeImpl() throws IOException;
+ protected abstract void flushImpl() throws IOException;
+
+ @Override
+ public final int write( ByteBuffer src ) throws IOException
+ {
+ return write( src, true );
+ }
@Override
- public final synchronized int write( ByteBuffer src ) throws IOException
+ public final void writeBuffered( ByteBuffer src ) throws IOException
+ {
+ write( src, false );
+ }
+
+ int write( ByteBuffer src, boolean flush ) throws IOException
{
if ( !isOpen() )
{
@@ -70,9 +74,9 @@ abstract class AbstractNoninterruptibleWritableChannel implements WritableByteCh
countWrittenBytes = src.remaining();
writeImpl( src );
src.position( src.limit() );
- if ( flushable )
+ if ( flush )
{
- flush();
+ flushImpl();
}
}
return countWrittenBytes;
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/Channels.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/Channels.java
index 65cb9b4..a536fc6 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/Channels.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/Channels.java
@@ -19,61 +19,195 @@ package org.apache.maven.surefire.util.internal;
* under the License.
*/
+import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousByteChannel;
+import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.ExecutionException;
import static java.util.Objects.requireNonNull;
/**
- * Converts {@link OutputStream}, {@link java.io.PrintStream}, {@link InputStream}
- * to the Java {@link java.nio.channels.Channel}.
+ * Converts {@link OutputStream}, {@link java.io.PrintStream}, {@link InputStream} to the Java {@link
+ * java.nio.channels.Channel}.
* <br>
- * We do not use the Java's utility class {@link java.nio.channels.Channels} because the utility
- * closes the stream as soon as the particular Thread is interrupted.
- * If the frameworks (Zookeeper, Netty) interrupts the thread, the communication channels become
- * closed and the JVM hangs. Therefore we developed internal utility which is safe for the Surefire.
+ * We do not use the Java's utility class {@link java.nio.channels.Channels} because the utility closes the stream as
+ * soon as the particular Thread is interrupted. If the frameworks (Zookeeper, Netty) interrupts the thread, the
+ * communication channels become closed and the JVM hangs. Therefore we developed internal utility which is safe for the
+ * Surefire.
*
* @since 3.0.0-M5
*/
public final class Channels
{
+ private static final int BUFFER_SIZE = 64 * 1024;
+
private Channels()
{
throw new IllegalStateException( "no instantiable constructor" );
}
- public static WritableByteChannel newChannel( @Nonnull OutputStream out )
+ public static WritableByteChannel newChannel( @Nonnull OutputStream out )
{
- return newChannel( out, false );
+ return newChannel( out, 0 );
}
- public static WritableByteChannel newFlushableChannel( @Nonnull OutputStream out )
+ public static WritableBufferedByteChannel newBufferedChannel( @Nonnull OutputStream out )
{
- return newChannel( out, true );
+ return newChannel( out, BUFFER_SIZE );
}
public static ReadableByteChannel newChannel( @Nonnull final InputStream is )
{
- requireNonNull( is, "the stream should not be null" );
+ return newChannel( is, 0 );
+ }
+
+ public static ReadableByteChannel newBufferedChannel( @Nonnull final InputStream is )
+ {
+ return newChannel( is, BUFFER_SIZE );
+ }
- if ( is instanceof FileInputStream && FileInputStream.class.equals( is.getClass() ) )
+ public static OutputStream newOutputStream( final AsynchronousByteChannel channel )
+ {
+ return new OutputStream()
{
- return ( (FileInputStream) is ).getChannel();
- }
+ @Override
+ public synchronized void write( byte[] b, int off, int len ) throws IOException
+ {
+ if ( off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0 )
+ {
+ throw new IndexOutOfBoundsException(
+ "b.length = " + b.length + ", off = " + off + ", len = " + len );
+ }
+ else if ( len > 0 )
+ {
+ ByteBuffer bb = ByteBuffer.wrap( b, off, len );
+ while ( bb.hasRemaining() )
+ {
+ try
+ {
+ channel.write( bb ).get();
+ }
+ catch ( ExecutionException e )
+ {
+ Throwable t = e.getCause();
+ throw new IOException( ( t == null ? e : t ).getLocalizedMessage(), t );
+ }
+ catch ( Exception e )
+ {
+ throw new IOException( e.getLocalizedMessage(), e );
+ }
+ }
+ }
+ }
+
+ @Override
+ public void write( int b ) throws IOException
+ {
+ write( new byte[] {(byte) b} );
+ }
+
+ @Override
+ public synchronized void close() throws IOException
+ {
+ if ( channel.isOpen() )
+ {
+ try
+ {
+ channel.close();
+ }
+ catch ( AsynchronousCloseException e )
+ {
+ // closed channel anyway
+ }
+ }
+ }
+ };
+ }
+
+ public static InputStream newInputStream( final AsynchronousByteChannel channel )
+ {
+ return new InputStream()
+ {
+ @Override
+ public synchronized int read( byte[] b, int off, int len ) throws IOException
+ {
+ if ( off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0 )
+ {
+ throw new IndexOutOfBoundsException(
+ "b.length = " + b.length + ", off = " + off + ", len = " + len );
+ }
+ else if ( len == 0 )
+ {
+ return 0;
+ }
+ ByteBuffer bb = ByteBuffer.wrap( b, off, len );
+ try
+ {
+ return channel.read( bb ).get();
+ }
+ catch ( ExecutionException e )
+ {
+ Throwable t = e.getCause();
+ throw new IOException( ( t == null ? e : t ).getLocalizedMessage(), t );
+ }
+ catch ( Exception e )
+ {
+ throw new IOException( e.getLocalizedMessage(), e );
+ }
+ }
+
+ @Override
+ public int read() throws IOException
+ {
+ int count;
+ byte[] b = new byte[1];
+ do
+ {
+ count = read( b, 0, 1 );
+ }
+ while ( count == 0 );
+
+ return count == -1 ? -1 : b[0];
+ }
+
+ @Override
+ public synchronized void close() throws IOException
+ {
+ if ( channel.isOpen() )
+ {
+ try
+ {
+ channel.close();
+ }
+ catch ( AsynchronousCloseException e )
+ {
+ // closed channel anyway
+ }
+ }
+ }
+ };
+ }
+
+ private static ReadableByteChannel newChannel( @Nonnull InputStream is, @Nonnegative int bufferSize )
+ {
+ requireNonNull( is, "the stream should not be null" );
+ final InputStream bis = bufferSize == 0 ? is : new BufferedInputStream( is, bufferSize );
return new AbstractNoninterruptibleReadableChannel()
{
@Override
protected int readImpl( ByteBuffer src ) throws IOException
{
- int count = is.read( src.array(), src.arrayOffset() + src.position(), src.remaining() );
+ int count = bis.read( src.array(), src.arrayOffset() + src.position(), src.remaining() );
if ( count > 0 )
{
src.position( count + src.position() );
@@ -84,38 +218,34 @@ public final class Channels
@Override
protected void closeImpl() throws IOException
{
- is.close();
+ bis.close();
}
};
}
- private static WritableByteChannel newChannel( @Nonnull final OutputStream out, final boolean flushable )
+ private static WritableBufferedByteChannel newChannel( @Nonnull OutputStream out, @Nonnegative int bufferSize )
{
requireNonNull( out, "the stream should not be null" );
+ final OutputStream bos = bufferSize == 0 ? out : new BufferedOutputStream( out, bufferSize );
- if ( out instanceof FileOutputStream && FileOutputStream.class.equals( out.getClass() ) )
- {
- return ( (FileOutputStream) out ).getChannel();
- }
-
- return new AbstractNoninterruptibleWritableChannel( flushable )
+ return new AbstractNoninterruptibleWritableChannel()
{
@Override
protected void writeImpl( ByteBuffer src ) throws IOException
{
- out.write( src.array(), src.arrayOffset() + src.position(), src.remaining() );
+ bos.write( src.array(), src.arrayOffset() + src.position(), src.remaining() );
}
@Override
protected void closeImpl() throws IOException
{
- out.close();
+ bos.close();
}
@Override
- public void flush() throws IOException
+ protected void flushImpl() throws IOException
{
- out.flush();
+ bos.flush();
}
};
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/WritableBufferedByteChannel.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/WritableBufferedByteChannel.java
new file mode 100644
index 0000000..7f64549
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/WritableBufferedByteChannel.java
@@ -0,0 +1,36 @@
+package org.apache.maven.surefire.util.internal;
+
+/*
+ * 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 java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * Extends {@link WritableByteChannel} with buffered (i.e. non-flushable) write
+ * operations, see {@link #writeBuffered(ByteBuffer)}. The messages are buffered
+ * and the channel is flushed after the buffer has overflew.
+ * <br>
+ * The method {@link #write(ByteBuffer)} flushes every written message.
+ */
+public interface WritableBufferedByteChannel extends WritableByteChannel
+{
+ void writeBuffered( ByteBuffer src ) throws IOException;
+}
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
index b125b0c..258b165 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/ForkingRunListenerTest.java
@@ -20,7 +20,6 @@ package org.apache.maven.surefire.booter;
*/
import junit.framework.TestCase;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.mockito.ArgumentCaptor;
import static org.fest.assertions.Assertions.assertThat;
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsReaderTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsReaderTest.java
index 7e3a685..0b64a42 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsReaderTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsReaderTest.java
@@ -38,7 +38,7 @@ import static java.nio.file.Files.write;
import static org.fest.assertions.Assertions.assertThat;
/**
- * The tests for {@link Channels#newChannel(InputStream)}.
+ * The tests for {@link Channels#newChannel(InputStream)} and {@link Channels#newBufferedChannel(InputStream)}.
*/
public class ChannelsReaderTest
{
@@ -107,6 +107,62 @@ public class ChannelsReaderTest
}
@Test
+ public void bufferedChannel() throws Exception
+ {
+ ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
+ ReadableByteChannel channel = Channels.newBufferedChannel( is );
+ ByteBuffer bb = ByteBuffer.allocate( 4 );
+
+ int countWritten = channel.read( bb );
+
+ assertThat( countWritten )
+ .isEqualTo( 3 );
+
+ assertThat( bb.arrayOffset() )
+ .isEqualTo( 0 );
+
+ assertThat( bb.position() )
+ .isEqualTo( 3 );
+
+ assertThat( bb.remaining() )
+ .isEqualTo( 1 );
+
+ assertThat( bb.limit() )
+ .isEqualTo( 4 );
+
+ assertThat( bb.capacity() )
+ .isEqualTo( 4 );
+
+ bb.flip();
+
+ assertThat( bb.arrayOffset() )
+ .isEqualTo( 0 );
+
+ assertThat( bb.position() )
+ .isEqualTo( 0 );
+
+ assertThat( bb.remaining() )
+ .isEqualTo( 3 );
+
+ assertThat( bb.limit() )
+ .isEqualTo( 3 );
+
+ assertThat( bb.capacity() )
+ .isEqualTo( 4 );
+
+ assertThat( bb.array() )
+ .isEqualTo( new byte[] {1, 2, 3, 0} );
+
+ assertThat( channel.isOpen() )
+ .isTrue();
+
+ channel.close();
+
+ assertThat( channel.isOpen() )
+ .isFalse();
+ }
+
+ @Test
public void biggerBuffer() throws Exception
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsWriterTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsWriterTest.java
index a1f6a66..35c9ddd 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsWriterTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/ChannelsWriterTest.java
@@ -38,7 +38,7 @@ import static java.nio.file.Files.readAllBytes;
import static org.fest.assertions.Assertions.assertThat;
/**
- * The tests for {@link Channels#newChannel(OutputStream)} and {@link Channels#newFlushableChannel(OutputStream)}.
+ * The tests for {@link Channels#newChannel(OutputStream)} and {@link Channels#newBufferedChannel(OutputStream)}.
*/
public class ChannelsWriterTest
{
@@ -63,7 +63,7 @@ public class ChannelsWriterTest
super.flush();
}
};
- WritableByteChannel channel = Channels.newFlushableChannel( out );
+ WritableByteChannel channel = Channels.newBufferedChannel( out );
ByteBuffer bb = ByteBuffer.wrap( new byte[] {1, 2, 3} );
int countWritten = channel.write( bb );
assertThat( countWritten )
@@ -119,6 +119,45 @@ public class ChannelsWriterTest
}
@Test
+ public void bufferedChannel() throws Exception
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ WritableBufferedByteChannel channel = Channels.newBufferedChannel( out );
+ ByteBuffer bb = ByteBuffer.allocate( 5 );
+ bb.put( (byte) 1 );
+ bb.put( (byte) 2 );
+ bb.put( (byte) 3 );
+
+ channel.writeBuffered( bb );
+
+ assertThat( out.toByteArray() )
+ .isEmpty();
+
+ channel.write( ByteBuffer.allocate( 0 ) );
+
+ assertThat( out.toByteArray() )
+ .isEmpty();
+
+ channel.write( ByteBuffer.wrap( new byte[] {4} ) );
+
+ assertThat( out.toByteArray() )
+ .hasSize( 4 )
+ .isEqualTo( new byte[] {1, 2, 3, 4} );
+
+ assertThat( bb.position() )
+ .isEqualTo( 3 );
+
+ assertThat( bb.limit() )
+ .isEqualTo( 3 );
+
+ assertThat( bb.capacity() )
+ .isEqualTo( 5 );
+
+ assertThat( channel.isOpen() )
+ .isTrue();
+ }
+
+ @Test
public void shouldFailAfterClosed() throws IOException
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index e437f97..28766f5 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -22,8 +22,6 @@ package org.apache.maven.surefire.booter;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.providerapi.CommandChainReader;
import org.apache.maven.surefire.providerapi.CommandListener;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
import java.io.EOFException;
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 46d9d74..1983ae2 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
@@ -23,8 +23,6 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelProcessorFactory;
import org.apache.maven.surefire.booter.spi.SurefireMasterProcessChannelProcessorFactory;
import org.apache.maven.surefire.providerapi.CommandListener;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
@@ -166,6 +164,15 @@ public final class ForkedBooter
}
finally
{
+ //noinspection ResultOfMethodCallIgnored
+ Thread.interrupted();
+
+ if ( eventChannel.checkError() )
+ {
+ DumpErrorSingleton.getSingleton()
+ .dumpText( "The channel (std/out or TCP/IP) failed to send a stream from this subprocess." );
+ }
+
acknowledgedExit();
}
}
@@ -382,9 +389,6 @@ public final class ForkedBooter
private void acknowledgedExit()
{
- //noinspection ResultOfMethodCallIgnored
- Thread.interrupted();
-
commandReader.addByeAckListener( new CommandListener()
{
@Override
@@ -397,7 +401,11 @@ public final class ForkedBooter
eventChannel.bye();
launchLastDitchDaemonShutdownThread( 0 );
long timeoutMillis = max( systemExitTimeoutInSeconds * ONE_SECOND_IN_MILLIS, ONE_SECOND_IN_MILLIS );
- acquireOnePermit( exitBarrier, timeoutMillis );
+ boolean timeoutElapsed = !acquireOnePermit( exitBarrier, timeoutMillis );
+ if ( timeoutElapsed )
+ {
+ eventChannel.sendExitError( null, false );
+ }
cancelPingScheduler();
commandReader.stop();
closeForkChannel();
@@ -544,15 +552,16 @@ public final class ForkedBooter
return pluginProcessChecker != null && pluginProcessChecker.canUse();
}
- private static void acquireOnePermit( Semaphore barrier, long timeoutMillis )
+ private static boolean acquireOnePermit( Semaphore barrier, long timeoutMillis )
{
try
{
- barrier.tryAcquire( timeoutMillis, MILLISECONDS );
+ return barrier.tryAcquire( timeoutMillis, MILLISECONDS );
}
catch ( InterruptedException e )
{
// cancel schedulers, stop the command reader and exit 0
+ return true;
}
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
index 568a2c5..47ffa01 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java
@@ -22,7 +22,6 @@ package org.apache.maven.surefire.booter;
import java.util.Collections;
import java.util.Iterator;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.util.CloseableIterator;
import org.apache.maven.surefire.util.TestsToRun;
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
index e8d3efb..df100e9 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
@@ -22,7 +22,7 @@ package org.apache.maven.surefire.booter.spi;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.DumpErrorSingleton;
import org.apache.maven.surefire.booter.MasterProcessCommand;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
import org.apache.maven.surefire.util.internal.ImmutableMap;
import javax.annotation.Nonnull;
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 a85e4ef..4a0c226 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
@@ -22,21 +22,22 @@ package org.apache.maven.surefire.booter.spi;
import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
import org.apache.maven.surefire.booter.DumpErrorSingleton;
import org.apache.maven.surefire.booter.ForkedProcessEventType;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.shared.codec.binary.Base64;
+import org.apache.maven.surefire.util.internal.WritableBufferedByteChannel;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
-import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -75,21 +76,20 @@ import static org.apache.maven.surefire.report.RunMode.RERUN_TEST_AFTER_FAILURE;
*/
public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEncoder
{
- static final String MAGIC_NUMBER_DELIMITED = ':' + MAGIC_NUMBER + ':';
private static final Base64 BASE64 = new Base64();
private static final Charset STREAM_ENCODING = US_ASCII;
private static final Charset STRING_ENCODING = UTF_8;
- protected final WritableByteChannel out;
+ private final WritableBufferedByteChannel out;
private final RunMode runMode;
- private volatile boolean trouble;
+ private final AtomicBoolean trouble = new AtomicBoolean();
- public LegacyMasterProcessChannelEncoder( @Nonnull WritableByteChannel out )
+ public LegacyMasterProcessChannelEncoder( @Nonnull WritableBufferedByteChannel out )
{
this( out, NORMAL_RUN );
}
- protected LegacyMasterProcessChannelEncoder( @Nonnull WritableByteChannel out, @Nonnull RunMode runMode )
+ protected LegacyMasterProcessChannelEncoder( @Nonnull WritableBufferedByteChannel out, @Nonnull RunMode runMode )
{
this.out = requireNonNull( out );
this.runMode = requireNonNull( runMode );
@@ -110,7 +110,7 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
@Override
public boolean checkError()
{
- return trouble;
+ return trouble.get();
}
@Override
@@ -121,56 +121,56 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
String key = entry.getKey();
String value = entry.getValue();
StringBuilder event = encode( BOOTERCODE_SYSPROPS, runMode, key, value );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, false );
}
}
@Override
public void testSetStarting( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testSetCompleted( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testStarting( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_STARTING, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_STARTING, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testSucceeded( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testFailed( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_FAILED, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_FAILED, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testSkipped( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testError( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_ERROR, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_ERROR, runMode, reportEntry, trimStackTraces, true );
}
@Override
public void testAssumptionFailure( ReportEntry reportEntry, boolean trimStackTraces )
{
- encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry, trimStackTraces );
+ encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry, trimStackTraces, true );
}
@Override
@@ -191,14 +191,14 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
{
String base64Message = toBase64( message );
StringBuilder event = encodeMessage( eventType, runMode.geRunName(), base64Message );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, false );
}
@Override
public void consoleInfoLog( String msg )
{
StringBuilder event = print( BOOTERCODE_CONSOLE_INFO.getOpcode(), msg );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, true );
}
@Override
@@ -206,7 +206,7 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
{
StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), null );
encode( encoded, msg, null, null );
- encodeAndPrintEvent( encoded );
+ encodeAndPrintEvent( encoded, true );
}
@Override
@@ -220,74 +220,75 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
{
StringBuilder encoded = encodeHeader( BOOTERCODE_CONSOLE_ERROR.getOpcode(), null );
encode( encoded, msg, null, ConsoleLoggerUtils.toString( t ) );
- encodeAndPrintEvent( encoded );
+ encodeAndPrintEvent( encoded, true );
}
@Override
public void consoleErrorLog( StackTraceWriter stackTraceWriter, boolean trimStackTraces )
{
- error( stackTraceWriter, trimStackTraces, BOOTERCODE_CONSOLE_ERROR );
+ error( stackTraceWriter, trimStackTraces, BOOTERCODE_CONSOLE_ERROR, true );
}
@Override
public void consoleDebugLog( String msg )
{
StringBuilder event = print( BOOTERCODE_CONSOLE_DEBUG.getOpcode(), msg );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, true );
}
@Override
public void consoleWarningLog( String msg )
{
StringBuilder event = print( BOOTERCODE_CONSOLE_WARNING.getOpcode(), msg );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, true );
}
@Override
public void bye()
{
- encodeOpcode( BOOTERCODE_BYE );
+ encodeOpcode( BOOTERCODE_BYE, true );
}
@Override
public void stopOnNextTest()
{
- encodeOpcode( BOOTERCODE_STOP_ON_NEXT_TEST );
+ encodeOpcode( BOOTERCODE_STOP_ON_NEXT_TEST, true );
}
@Override
public void acquireNextTest()
{
- encodeOpcode( BOOTERCODE_NEXT_TEST );
+ encodeOpcode( BOOTERCODE_NEXT_TEST, true );
}
@Override
- public void sendExitEvent( StackTraceWriter stackTraceWriter, boolean trimStackTraces )
+ public void sendExitError( StackTraceWriter stackTraceWriter, boolean trimStackTraces )
{
- error( stackTraceWriter, trimStackTraces, BOOTERCODE_JVM_EXIT_ERROR );
+ error( stackTraceWriter, trimStackTraces, BOOTERCODE_JVM_EXIT_ERROR, true );
}
- private void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces, ForkedProcessEventType event )
+ private void error( StackTraceWriter stackTraceWriter, boolean trimStackTraces, ForkedProcessEventType event,
+ @SuppressWarnings( "SameParameterValue" ) boolean sendImmediately )
{
StringBuilder encoded = encodeHeader( event.getOpcode(), null );
encode( encoded, stackTraceWriter, trimStackTraces );
- encodeAndPrintEvent( encoded );
+ encodeAndPrintEvent( encoded, sendImmediately );
}
private void encode( ForkedProcessEventType operation, RunMode runMode, ReportEntry reportEntry,
- boolean trimStackTraces )
+ boolean trimStackTraces, @SuppressWarnings( "SameParameterValue" ) boolean sendImmediately )
{
StringBuilder event = encode( operation.getOpcode(), runMode.geRunName(), reportEntry, trimStackTraces );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, sendImmediately );
}
- private void encodeOpcode( ForkedProcessEventType operation )
+ private void encodeOpcode( ForkedProcessEventType operation, boolean sendImmediately )
{
StringBuilder event = encodeOpcode( operation.getOpcode(), null );
- encodeAndPrintEvent( event );
+ encodeAndPrintEvent( event, sendImmediately );
}
- private void encodeAndPrintEvent( StringBuilder event )
+ private void encodeAndPrintEvent( StringBuilder event, boolean sendImmediately )
{
try
{
@@ -298,7 +299,16 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
.toString()
.getBytes( STREAM_ENCODING );
- out.write( ByteBuffer.wrap( array ) );
+ ByteBuffer bb = ByteBuffer.wrap( array );
+
+ if ( sendImmediately )
+ {
+ out.write( bb );
+ }
+ else
+ {
+ out.writeBuffered( bb );
+ }
}
catch ( ClosedChannelException e )
{
@@ -307,9 +317,11 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
}
catch ( IOException e )
{
- DumpErrorSingleton.getSingleton()
- .dumpException( e );
- trouble = true;
+ if ( trouble.compareAndSet( false, true ) )
+ {
+ DumpErrorSingleton.getSingleton()
+ .dumpException( e );
+ }
}
}
@@ -415,7 +427,7 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
}
/**
- * Used in {@link #bye()}, {@link #stopOnNextTest()} and {@link #encodeOpcode(ForkedProcessEventType)}
+ * Used in {@link #bye()}, {@link #stopOnNextTest()} and {@link #encodeOpcode(ForkedProcessEventType, boolean)}
* and private methods extending the buffer.
*
* @param operation opcode
@@ -425,7 +437,9 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
static StringBuilder encodeOpcode( String operation, String runMode )
{
StringBuilder s = new StringBuilder( 128 )
- .append( MAGIC_NUMBER_DELIMITED )
+ .append( ':' )
+ .append( MAGIC_NUMBER )
+ .append( ':' )
.append( operation )
.append( ':' );
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 5713b99..c09516b 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
@@ -19,15 +19,14 @@ package org.apache.maven.surefire.booter.spi;
* under the License.
*/
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
import java.io.IOException;
import java.net.MalformedURLException;
-import static org.apache.maven.surefire.util.internal.Channels.newChannel;
-import static org.apache.maven.surefire.util.internal.Channels.newFlushableChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
/**
* Producer of encoder and decoder for process pipes.
@@ -57,13 +56,13 @@ public class LegacyMasterProcessChannelProcessorFactory
@Override
public MasterProcessChannelDecoder createDecoder()
{
- return new LegacyMasterProcessChannelDecoder( newChannel( System.in ) );
+ return new LegacyMasterProcessChannelDecoder( newBufferedChannel( System.in ) );
}
@Override
public MasterProcessChannelEncoder createEncoder()
{
- return new LegacyMasterProcessChannelEncoder( newFlushableChannel( System.out ) );
+ return new LegacyMasterProcessChannelEncoder( newBufferedChannel( System.out ) );
}
@Override
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 1893009..6f52756 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
@@ -19,16 +19,28 @@ package org.apache.maven.surefire.booter.spi;
* under the License.
*/
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
+import java.net.SocketOption;
import java.net.URI;
import java.net.URISyntaxException;
-import java.nio.channels.SocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.util.concurrent.ExecutionException;
+
+import static java.net.StandardSocketOptions.SO_KEEPALIVE;
+import static java.net.StandardSocketOptions.SO_REUSEADDR;
+import static java.net.StandardSocketOptions.TCP_NODELAY;
+import static java.nio.channels.AsynchronousChannelGroup.withFixedThreadPool;
+import static java.nio.channels.AsynchronousSocketChannel.open;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newInputStream;
+import static org.apache.maven.surefire.util.internal.Channels.newOutputStream;
+import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
/**
* Producer of TCP/IP encoder and decoder.
@@ -40,7 +52,7 @@ import java.nio.channels.SocketChannel;
public class SurefireMasterProcessChannelProcessorFactory
implements MasterProcessChannelProcessorFactory
{
- private volatile SocketChannel channel;
+ private volatile AsynchronousSocketChannel clientSocketChannel;
@Override
public boolean canUse( String channelConfig )
@@ -59,32 +71,52 @@ public class SurefireMasterProcessChannelProcessorFactory
try
{
URI uri = new URI( channelConfig );
- channel = SocketChannel.open( new InetSocketAddress( uri.getHost(), uri.getPort() ) );
+ InetSocketAddress hostAddress = new InetSocketAddress( uri.getHost(), uri.getPort() );
+ clientSocketChannel = open( withFixedThreadPool( 2, newDaemonThreadFactory() ) );
+ setTrueOptions( SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE );
+ clientSocketChannel.connect( hostAddress ).get();
}
- catch ( URISyntaxException e )
+ catch ( URISyntaxException | InterruptedException e )
{
throw new IOException( e.getLocalizedMessage(), e );
}
+ catch ( ExecutionException e )
+ {
+ throw new IOException( e.getLocalizedMessage(), e.getCause() );
+ }
}
@Override
public MasterProcessChannelDecoder createDecoder()
{
- return new LegacyMasterProcessChannelDecoder( channel );
+ return new LegacyMasterProcessChannelDecoder( newBufferedChannel( newInputStream( clientSocketChannel ) ) );
}
@Override
public MasterProcessChannelEncoder createEncoder()
{
- return new LegacyMasterProcessChannelEncoder( channel );
+ return new LegacyMasterProcessChannelEncoder( newBufferedChannel( newOutputStream( clientSocketChannel ) ) );
}
@Override
public void close() throws IOException
{
- if ( channel != null )
+ if ( clientSocketChannel != null && clientSocketChannel.isOpen() )
+ {
+ clientSocketChannel.close();
+ }
+ }
+
+ @SafeVarargs
+ private final void setTrueOptions( SocketOption<Boolean>... options )
+ throws IOException
+ {
+ for ( SocketOption<Boolean> option : options )
{
- channel.close();
+ if ( clientSocketChannel.supportedOptions().contains( option ) )
+ {
+ clientSocketChannel.setOption( option, true );
+ }
}
}
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index edaae08..1c85048 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -23,8 +23,8 @@ import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.internal.WritableBufferedByteChannel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -34,7 +34,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.nio.channels.WritableByteChannel;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
@@ -44,7 +43,8 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import static java.nio.channels.Channels.newChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newChannel;
import static org.fest.assertions.Assertions.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -262,8 +262,8 @@ public class CommandReaderTest
}
}
- private static WritableByteChannel nul()
+ private static WritableBufferedByteChannel nul()
{
- return newChannel( new PrintStream( new ByteArrayOutputStream() ) );
+ return newBufferedChannel( new PrintStream( new ByteArrayOutputStream() ) );
}
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
index fa8011d..5604fd1 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterMockTest.java
@@ -23,8 +23,6 @@ import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
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.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
import org.junit.Rule;
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
index 3f6d148..aac78f7 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/ForkedBooterTest.java
@@ -151,8 +151,9 @@ public class ForkedBooterTest
public void testBarrier() throws Exception
{
Semaphore semaphore = new Semaphore( 2 );
- invokeMethod( ForkedBooter.class, "acquireOnePermit", semaphore, 30_000L );
+ boolean acquiredOnePermit = invokeMethod( ForkedBooter.class, "acquireOnePermit", semaphore, 30_000L );
+ assertThat( acquiredOnePermit ).isTrue();
assertThat( semaphore.availablePermits() ).isEqualTo( 1 );
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
index acfcac3..761e30f 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoderTest.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.util.internal.ObjectUtils;
+import org.apache.maven.surefire.util.internal.WritableBufferedByteChannel;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
@@ -34,17 +35,17 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Map;
-import static java.nio.channels.Channels.newChannel;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.copyOfRange;
-import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.MAGIC_NUMBER_DELIMITED;
-import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.toBase64;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
import static org.apache.maven.surefire.shared.codec.binary.Base64.encodeBase64String;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encode;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeHeader;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeMessage;
import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.encodeOpcode;
+import static org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelEncoder.toBase64;
import static org.apache.maven.surefire.booter.ForkedProcessEventType.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.booter.ForkedProcessEventType.MAGIC_NUMBER;
import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -71,7 +72,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void shouldHaveSystemProperty()
{
StringBuilder actualEncoded = encode( BOOTERCODE_SYSPROPS, NORMAL_RUN, "arg1", "arg2" );
- String expected = MAGIC_NUMBER_DELIMITED + BOOTERCODE_SYSPROPS.getOpcode()
+ String expected = ':' + MAGIC_NUMBER + ':' + BOOTERCODE_SYSPROPS.getOpcode()
+ ":normal-run:UTF-8:YXJnMQ==:YXJnMg==:";
assertThat( actualEncoded.toString() )
@@ -235,7 +236,7 @@ public class LegacyMasterProcessChannelEncoderTest
);
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetStarting( reportEntry, true );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -266,7 +267,7 @@ public class LegacyMasterProcessChannelEncoderTest
assertThat( printedLines.readLine() ).isNull();
out = Stream.newStream();
- encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetStarting( reportEntry, false );
printedLines = out.newReader( UTF_8 );
@@ -334,7 +335,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSetCompleted( reportEntry, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -402,7 +403,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testStarting( reportEntry, true );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -470,7 +471,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSucceeded( reportEntry, true );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -538,7 +539,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testFailed( reportEntry, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -605,7 +606,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testSkipped( reportEntry, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -671,7 +672,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testError( reportEntry, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -735,7 +736,7 @@ public class LegacyMasterProcessChannelEncoderTest
String encodedMessage = encodeBase64String( toArray( UTF_8.encode( reportEntry.getMessage() ) ) );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.testAssumptionFailure( reportEntry, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -770,7 +771,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testBye() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.bye();
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -783,7 +784,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testStopOnNextTest() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.stopOnNextTest();
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -796,7 +797,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testAcquireNextTest() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.acquireNextTest();
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -821,7 +822,7 @@ public class LegacyMasterProcessChannelEncoderTest
.isEqualTo( ":maven-surefire-event:some-opcode:normal-run:UTF-8:msg:" );
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoded = encoder.print( "some-opcode", "msg" );
assertThat( encoded.toString() )
.isEqualTo( ":maven-surefire-event:some-opcode:UTF-8:bXNn:" );
@@ -835,7 +836,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleInfo()
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleInfoLog( "msg" );
@@ -854,7 +855,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleError()
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleErrorLog( "msg" );
@@ -872,7 +873,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleErrorLog1() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleErrorLog( new Exception( "msg" ) );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -885,7 +886,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleErrorLog2() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleErrorLog( "msg2", new Exception( "msg" ) );
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -898,7 +899,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleErrorLog3() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
@@ -917,7 +918,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleDebug()
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleDebugLog( "msg" );
@@ -936,7 +937,7 @@ public class LegacyMasterProcessChannelEncoderTest
public void testConsoleWarning()
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
encoder.consoleWarningLog( "msg" );
@@ -955,9 +956,11 @@ public class LegacyMasterProcessChannelEncoderTest
public void testStdOutStream() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel channel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
encoder.stdOut( "msg", false );
+ channel.close();
String expected = ":maven-surefire-event:std-out-stream:normal-run:UTF-8:bXNn:";
@@ -972,9 +975,11 @@ public class LegacyMasterProcessChannelEncoderTest
public void testStdOutStreamLn() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel channel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
encoder.stdOut( "msg", true );
+ channel.close();
String expected = ":maven-surefire-event:std-out-stream-new-line:normal-run:UTF-8:bXNn:";
@@ -989,9 +994,11 @@ public class LegacyMasterProcessChannelEncoderTest
public void testStdErrStream() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel channel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
encoder.stdErr( "msg", false );
+ channel.close();
String expected = ":maven-surefire-event:std-err-stream:normal-run:UTF-8:bXNn:";
@@ -1006,9 +1013,11 @@ public class LegacyMasterProcessChannelEncoderTest
public void testStdErrStreamLn() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel channel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
encoder.stdErr( "msg", true );
+ channel.close();
String expected = ":maven-surefire-event:std-err-stream-new-line:normal-run:UTF-8:bXNn:";
@@ -1024,11 +1033,13 @@ public class LegacyMasterProcessChannelEncoderTest
public void shouldCountSameNumberOfSystemProperties() throws IOException
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ WritableBufferedByteChannel channel = newBufferedChannel( out );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( channel );
Map<String, String> sysProps = ObjectUtils.systemProps();
int expectedSize = sysProps.size();
encoder.sendSystemProperties( sysProps );
+ channel.close();
LineNumberReader printedLines = out.newReader( UTF_8 );
@@ -1048,13 +1059,13 @@ public class LegacyMasterProcessChannelEncoderTest
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
- encoder.sendExitEvent( stackTraceWriter, false );
+ encoder.sendExitError( stackTraceWriter, false );
LineNumberReader printedLines = out.newReader( UTF_8 );
assertThat( printedLines.readLine() )
@@ -1066,13 +1077,13 @@ public class LegacyMasterProcessChannelEncoderTest
{
Stream out = Stream.newStream();
- LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newChannel( out ) );
+ LegacyMasterProcessChannelEncoder encoder = new LegacyMasterProcessChannelEncoder( newBufferedChannel( out ) );
StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
when( stackTraceWriter.getThrowable() ).thenReturn( new SafeThrowable( "1" ) );
when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( "2" );
when( stackTraceWriter.writeTraceToString() ).thenReturn( "3" );
when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( "4" );
- encoder.sendExitEvent( stackTraceWriter, true );
+ encoder.sendExitError( stackTraceWriter, true );
LineNumberReader printedLines = out.newReader( UTF_8 );
assertThat( printedLines.readLine() )
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineStreams.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineStreams.java
index cb57b9c..ddc43ea 100644
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineStreams.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineStreams.java
@@ -28,8 +28,7 @@ import java.nio.channels.ClosedChannelException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
-import static org.apache.maven.surefire.util.internal.Channels.newChannel;
-import static org.apache.maven.surefire.util.internal.Channels.newFlushableChannel;
+import static org.apache.maven.surefire.util.internal.Channels.newBufferedChannel;
/**
*
@@ -44,12 +43,12 @@ public final class CommandlineStreams implements Closeable
public CommandlineStreams( @Nonnull Process process )
{
InputStream stdOutStream = process.getInputStream();
- stdOutChannel = newChannel( stdOutStream );
+ stdOutChannel = newBufferedChannel( stdOutStream );
InputStream stdErrStream = process.getErrorStream();
- stdErrChannel = newChannel( stdErrStream );
+ stdErrChannel = newBufferedChannel( stdErrStream );
- stdInChannel = newFlushableChannel( process.getOutputStream() );
+ stdInChannel = newBufferedChannel( process.getOutputStream() );
}
public ReadableByteChannel getStdOutChannel()
diff --git a/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelProcessorFactory.java b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelProcessorFactory.java
index 989a52d..c1c5c3c 100644
--- a/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelProcessorFactory.java
+++ b/surefire-extensions-spi/src/main/java/org/apache/maven/surefire/spi/MasterProcessChannelProcessorFactory.java
@@ -19,8 +19,8 @@ package org.apache.maven.surefire.spi;
* under the License.
*/
-import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
-import org.apache.maven.surefire.providerapi.MasterProcessChannelEncoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.booter.MasterProcessChannelEncoder;
import java.io.Closeable;
import java.io.IOException;
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java
index 21b92b9..1fd03a5 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java
@@ -19,13 +19,13 @@ package org.apache.maven.surefire.its;
* under the License.
*/
-import com.googlecode.junittoolbox.ParallelParameterized;
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 org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
@@ -40,7 +40,7 @@ import static org.hamcrest.Matchers.equalTo;
*
* @author Kristian Rosenvold
*/
-@RunWith( ParallelParameterized.class )
+@RunWith( Parameterized.class )
public class ConsoleOutputIT
extends SurefireJUnit4IntegrationTestCase
{
@@ -67,7 +67,7 @@ public class ConsoleOutputIT
public void properNewlinesAndEncodingWithDefaultEncodings() throws Exception
{
OutputValidator outputValidator = unpack().forkOnce().executeTest();
- validate( outputValidator, profileId == null, true );
+ validate( outputValidator, true );
}
@Test
@@ -77,7 +77,7 @@ public class ConsoleOutputIT
.forkOnce()
.argLine( "-Dfile.encoding=UTF-16" )
.executeTest();
- validate( outputValidator, profileId == null, true );
+ validate( outputValidator, true );
}
@Test
@@ -86,7 +86,7 @@ public class ConsoleOutputIT
OutputValidator outputValidator = unpack()
.forkNever()
.executeTest();
- validate( outputValidator, false, false );
+ validate( outputValidator, false );
}
private SurefireLauncher unpack()
@@ -103,7 +103,7 @@ public class ConsoleOutputIT
return launcher;
}
- private void validate( final OutputValidator outputValidator, boolean includeShutdownHook, boolean canFork )
+ private void validate( final OutputValidator outputValidator, boolean canFork )
throws Exception
{
TestFile xmlReportFile = outputValidator.getSurefireReportsXmlFile( "TEST-consoleOutput.Test1.xml" );
@@ -116,13 +116,6 @@ public class ConsoleOutputIT
outputFile.assertContainsText( "SoutLine" );
outputFile.assertContainsText( "äöüß" );
- if ( includeShutdownHook )
- {
- //todo it should not be reported in the last test which is completed
- //todo this text should be in null-output.txt
- outputFile.assertContainsText( "Printline in shutdown hook" );
- }
-
String cls = profileId == null ? LEGACY_FORK_NODE : SUREFIRE_FORK_NODE;
if ( canFork )
diff --git a/surefire-its/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java b/surefire-its/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java
index 93e6a83..db74acf 100644
--- a/surefire-its/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java
+++ b/surefire-its/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java
@@ -29,26 +29,8 @@ import static org.junit.Assert.fail;
public class Test1
{
- static
+ public Test1()
{
- System.out.println("Printline in static block");
- Runtime.getRuntime().addShutdownHook( new Thread( ){
- @Override
- public void run()
- {
- System.out.println( "Printline in shutdown hook" );
- }
- });
- }
-
- @Override
- protected void finalize()
- throws Throwable
- {
- System.out.println( "Printline in finalizer" );
- }
-
- public Test1(){
System.out.println("In constructor");
}
diff --git a/surefire-its/src/test/resources/consoleoutput-noisy/src/test/java/consoleoutput_noisy/Test3.java b/surefire-its/src/test/resources/consoleoutput-noisy/src/test/java/consoleoutput_noisy/Test3.java
new file mode 100644
index 0000000..84c6198
--- /dev/null
+++ b/surefire-its/src/test/resources/consoleoutput-noisy/src/test/java/consoleoutput_noisy/Test3.java
@@ -0,0 +1,52 @@
+package consoleoutput_noisy;
+
+/*
+ * 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.junit.Test;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.io.File;
+
+/**
+ *
+ */
+public class Test3
+{
+ @Test
+ public void test() throws Exception
+ {
+ long t1 = System.currentTimeMillis();
+ System.out.println( "t1 = " + t1 );
+ for ( int i = 0; i < 320_000; i++ )
+ {
+ System.out.println( "01234567890123456789012345678901234567890123456789"
+ + "01234567890123456789012345678901234567890123456789" );
+ }
+ long t2 = System.currentTimeMillis();
+ System.out.println( "t2 = " + t2 );
+
+ File target = new File( System.getProperty( "user.dir" ) );
+ new File( target, ( t2 - t1 ) + "" )
+ .createNewFile();
+ }
+}