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 2019/12/02 03:01:06 UTC

[maven-surefire] branch cli updated: substitutes the old call executeCommandLineAsCallable() - (process call with all stream handlers)

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

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


The following commit(s) were added to refs/heads/cli by this push:
     new 71b8fd3  substitutes the old call executeCommandLineAsCallable() - (process call with all stream handlers)
71b8fd3 is described below

commit 71b8fd300a1bfd792bc970c2acfda9ee496a8282
Author: tibordigana <ti...@apache.org>
AuthorDate: Sun Dec 1 02:39:52 2019 +0100

    substitutes the old call executeCommandLineAsCallable() - (process call with all stream handlers)
---
 .../plugin/surefire/booterclient/ForkStarter.java  | 53 +++++++++++---
 surefire-extensions-api/pom.xml                    |  7 +-
 .../extensions/util/CommandlineExecutor.java       | 11 ++-
 .../extensions/util/CommandlineStreams.java        |  3 +-
 .../util/FlushableWritableByteChannel.java         |  3 +-
 .../extensions/util/LineConsumerThread.java        | 25 +++++--
 .../surefire/extensions/util/StreamFeeder.java     | 85 ++++++++++++++++++++++
 7 files changed, 163 insertions(+), 24 deletions(-)

diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index e3a76da..4b5e4fd 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -33,7 +33,10 @@ import org.apache.maven.plugin.surefire.booterclient.output.NativeStdErrStreamCo
 import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.shared.utils.cli.CommandLineCallable;
+import org.apache.maven.surefire.extensions.util.CommandlineExecutor;
+import org.apache.maven.surefire.extensions.util.CommandlineStreams;
+import org.apache.maven.surefire.extensions.util.LineConsumerThread;
+import org.apache.maven.surefire.extensions.util.StreamFeeder;
 import org.apache.maven.surefire.shared.utils.cli.CommandLineException;
 import org.apache.maven.surefire.booter.AbstractPathConfiguration;
 import org.apache.maven.surefire.booter.KeyValueSource;
@@ -61,6 +64,7 @@ import java.util.Queue;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
@@ -75,7 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 import static java.lang.StrictMath.min;
 import static java.lang.System.currentTimeMillis;
 import static java.lang.Thread.currentThread;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static java.util.Collections.addAll;
 import static java.util.Objects.requireNonNull;
 import static java.util.concurrent.Executors.newScheduledThreadPool;
@@ -88,7 +91,6 @@ import static org.apache.maven.plugin.surefire.booterclient.ForkNumberBucket.dra
 import static org.apache.maven.plugin.surefire.booterclient.ForkNumberBucket.returnNumber;
 import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream
                       .TestLessInputStreamBuilder;
-import static org.apache.maven.surefire.shared.utils.cli.CommandLineUtils.executeCommandLineAsCallable;
 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.removeShutdownHook;
 import static org.apache.maven.surefire.booter.SystemPropertyManager.writePropertiesFile;
@@ -217,6 +219,11 @@ public class ForkStarter
                 removeShutdownHook( inputStreamCloserHook );
             }
         }
+
+        void addCloseable( Closeable closeable )
+        {
+            testProvidingInputStream.add( closeable );
+        }
     }
 
     public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
@@ -603,30 +610,54 @@ public class ForkStarter
         Integer result = null;
         RunResult runResult = null;
         SurefireBooterForkException booterForkException = null;
+        StreamFeeder in = null;
+        LineConsumerThread out = null;
+        LineConsumerThread err = null;
         try
         {
             NativeStdErrStreamConsumer stdErrConsumer =
                     new NativeStdErrStreamConsumer( forkClient.getDefaultReporterFactory() );
-
-            CommandLineCallable future =
-                    executeCommandLineAsCallable( cli, testProvidingInputStream, threadedStreamConsumer,
-                                                        stdErrConsumer, 0, closer, ISO_8859_1 );
-
             currentForkClients.add( forkClient );
 
-            result = future.call();
+            // default impl of the extension - solves everything including the encoder/decoder, Process starter,
+            // adaptation of the streams to pipes and sockets
+            // non-default impl may use another classes and not the LineConsumerThread, StreamFeeder - freedom
+            // BEGIN: beginning of the call of the extension
+            CountDownLatch endOfStreamsCountdown = new CountDownLatch( 2 );
+            CommandlineExecutor exec = new CommandlineExecutor( cli, closer, endOfStreamsCountdown );
+            CommandlineStreams streams = exec.execute();
+            in = new StreamFeeder( "std-in-fork-" + forkNumber, streams.getStdInChannel(), testProvidingInputStream );
+            closer.addCloseable( in );
+            in.start();
+            out = new LineConsumerThread( "std-out-fork-" + forkNumber, streams.getStdOutChannel(),
+                                          threadedStreamConsumer, endOfStreamsCountdown );
+            closer.addCloseable( out );
+            out.start();
+            err = new LineConsumerThread( "std-err-fork-" + forkNumber, streams.getStdErrChannel(),
+                                          stdErrConsumer, endOfStreamsCountdown );
+            closer.addCloseable( err );
+            err.start();
+            result = exec.awaitExit();
+            // END: end of the call of the extension
 
             if ( forkClient.hadTimeout() )
             {
                 runResult = timeout( forkClient.getDefaultReporterFactory().getGlobalRunStatistics().getRunResult() );
             }
-            else if ( result == null || result != SUCCESS )
+            else if ( result != SUCCESS )
             {
                 booterForkException =
                         new SurefireBooterForkException( "Error occurred in starting fork, check output in log" );
             }
         }
-        catch ( CommandLineException e )
+        catch ( InterruptedException e )
+        {
+            // maybe implement it in the Future.cancel() of the extension or similar
+            in.disable();
+            out.disable();
+            err.disable();
+        }
+        catch ( CommandLineException | IOException e )
         {
             runResult = failure( forkClient.getDefaultReporterFactory().getGlobalRunStatistics().getRunResult(), e );
             String cliErr = e.getLocalizedMessage();
diff --git a/surefire-extensions-api/pom.xml b/surefire-extensions-api/pom.xml
index a9d940b..5a79731 100644
--- a/surefire-extensions-api/pom.xml
+++ b/surefire-extensions-api/pom.xml
@@ -43,6 +43,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jacoco</groupId>
             <artifactId>org.jacoco.agent</artifactId>
             <classifier>runtime</classifier>
@@ -92,4 +97,4 @@
         </plugins>
     </build>
 
-</project>
\ No newline at end of file
+</project>
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineExecutor.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineExecutor.java
index 9415bfe..55f62e3 100644
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineExecutor.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CommandlineExecutor.java
@@ -50,9 +50,12 @@ import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.remov
  *     int exitCode = exec.awaitExit();
  *     // process exitCode
  * }
- * catch ( InterruptedException | IOException | CommandLineException e )
+ * catch ( InterruptedException e )
+ * {
+ *     lineConsumerThread.disable();
+ * }
+ * catch ( IOException | CommandLineException e )
  * {
- *     // lineConsumerThread.disable();
  *     // handle the exceptions
  * }
  * } </pre>
@@ -68,6 +71,10 @@ public class CommandlineExecutor implements Closeable
     public CommandlineExecutor( Commandline cli,
                                 Closeable closeAfterProcessTermination, CountDownLatch endOfStreamsCountdown )
     {
+        // now the surefire-extension-api is dependent on CLI without casting generic type T to unrelated object
+        // and the user would not use maven-surefire-common nothing but the only surefire-extension-api
+        // because maven-surefire-common is used for MOJO plugin and not the user's extensions. The user does not need
+        // to see all MOJO impl. Only the surefire-api, surefire-logger-api and surefire-extension-api.
         this.cli = cli;
         this.closeAfterProcessTermination = closeAfterProcessTermination;
         this.endOfStreamsCountdown = endOfStreamsCountdown;
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 e60b2c6..43ec328 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
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.extensions.util;
  * under the License.
  */
 
+import javax.annotation.Nonnull;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
@@ -39,7 +40,7 @@ public final class CommandlineStreams implements Closeable
     private final WritableByteChannel stdInChannel;
     private volatile boolean closed;
 
-    public CommandlineStreams( Process process )
+    public CommandlineStreams( @Nonnull Process process )
     {
         InputStream stdOutStream = process.getInputStream();
         stdOutChannel = newChannel( stdOutStream );
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/FlushableWritableByteChannel.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/FlushableWritableByteChannel.java
index b769407..e4112f2 100644
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/FlushableWritableByteChannel.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/FlushableWritableByteChannel.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.extensions.util;
  * under the License.
  */
 
+import javax.annotation.Nonnull;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
@@ -34,7 +35,7 @@ final class FlushableWritableByteChannel implements WritableByteChannel
     private final OutputStream os;
     private final WritableByteChannel channel;
 
-    private FlushableWritableByteChannel( OutputStream os )
+    private FlushableWritableByteChannel( @Nonnull OutputStream os )
     {
         this.os = os;
         this.channel = newChannel( os );
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/LineConsumerThread.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/LineConsumerThread.java
index 771cdc5..f0f39f3 100644
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/LineConsumerThread.java
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/LineConsumerThread.java
@@ -21,6 +21,9 @@ package org.apache.maven.surefire.extensions.util;
 
 import org.apache.maven.surefire.shared.utils.cli.StreamConsumer;
 
+import javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.IOException;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.charset.Charset;
 import java.util.Scanner;
@@ -29,23 +32,23 @@ import java.util.concurrent.CountDownLatch;
 /**
  *
  */
-public final class LineConsumerThread extends Thread
+public final class LineConsumerThread extends Thread implements Closeable
 {
     private final Scanner scanner;
     private final StreamConsumer consumer;
     private final CountDownLatch endOfStreamsCountdown;
     private volatile boolean disabled;
 
-    public LineConsumerThread( String threadName,
-                               ReadableByteChannel channel, StreamConsumer consumer,
-                               CountDownLatch endOfStreamsCountdown )
+    public LineConsumerThread( @Nonnull String threadName,
+                               @Nonnull ReadableByteChannel channel, @Nonnull StreamConsumer consumer,
+                               @Nonnull CountDownLatch endOfStreamsCountdown )
     {
-        this( threadName, channel, consumer, Charset.defaultCharset(), endOfStreamsCountdown );
+        this( threadName, channel, consumer, endOfStreamsCountdown, Charset.defaultCharset() );
     }
 
-    public LineConsumerThread( String threadName,
-                               ReadableByteChannel channel, StreamConsumer consumer, Charset encoding,
-                               CountDownLatch endOfStreamsCountdown )
+    public LineConsumerThread( @Nonnull String threadName,
+                               @Nonnull ReadableByteChannel channel, @Nonnull StreamConsumer consumer,
+                               @Nonnull CountDownLatch endOfStreamsCountdown, @Nonnull Charset encoding )
     {
         setName( threadName );
         setDaemon( true );
@@ -91,4 +94,10 @@ public final class LineConsumerThread extends Thread
     {
         disabled = true;
     }
+
+    @Override
+    public void close() throws IOException
+    {
+        scanner.close();
+    }
 }
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java
new file mode 100644
index 0000000..255104b
--- /dev/null
+++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java
@@ -0,0 +1,85 @@
+package org.apache.maven.surefire.extensions.util;
+
+/*
+ * 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 javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ *
+ */
+public class StreamFeeder extends Thread implements Closeable
+{
+    private final WritableByteChannel channel;
+    private final InputStream is;
+
+    private volatile boolean disabled;
+    private volatile boolean closed;
+    private volatile Throwable exception;
+
+    public StreamFeeder( @Nonnull String threadName, @Nonnull WritableByteChannel channel, @Nonnull InputStream is )
+    {
+        setName( threadName );
+        setDaemon( true );
+        this.channel = channel;
+        this.is = is;
+    }
+
+    @Override
+    public void run()
+    {
+        try
+        {
+            for ( int data = is.read(); !closed && data != -1; data = is.read()  )
+            {
+                if ( !disabled )
+                {
+                    // todo use CommandReader interface instead of InputStream. Then we would write ByteBuffer.
+                    channel.write( ByteBuffer.wrap( new byte[] {(byte) data} ) );
+                }
+            }
+        }
+        catch ( IOException | NonWritableChannelException e )
+        {
+            exception = e.getCause() == null ? e : e.getCause();
+        }
+    }
+
+    public void disable()
+    {
+        disabled = true;
+    }
+
+    public Throwable getException()
+    {
+        return exception;
+    }
+
+    @Override
+    public void close()
+    {
+        closed = true;
+    }
+}