View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.exec.issues;
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.PipedInputStream;
24  import java.io.PipedOutputStream;
25  import java.time.Duration;
26  
27  import org.apache.commons.exec.CommandLine;
28  import org.apache.commons.exec.DefaultExecuteResultHandler;
29  import org.apache.commons.exec.DefaultExecutor;
30  import org.apache.commons.exec.Executor;
31  import org.apache.commons.exec.PumpStreamHandler;
32  import org.junit.jupiter.api.Test;
33  import org.junit.jupiter.api.condition.DisabledOnOs;
34  import org.junit.jupiter.api.condition.OS;
35  
36  /**
37   * Test EXEC-44 (https://issues.apache.org/jira/browse/EXEC-44).
38   */
39  class Exec49Test {
40  
41      private static final Duration WAIT = Duration.ofSeconds(10);
42      private final Executor exec = DefaultExecutor.builder().get();
43  
44      /**
45       * The issue was detected when trying to capture stdout/stderr with a PipedOutputStream and then pass that to a PipedInputStream. The following code will
46       * produce the error. The reason for the error is the PipedOutputStream is not being closed correctly, causing the PipedInputStream to break.
47       *
48       * @throws Exception the test failed
49       */
50      @Test
51      @DisabledOnOs(OS.WINDOWS)
52      void testExec49Part1() throws Exception {
53          final CommandLine cl = CommandLine.parse("/bin/ls");
54          cl.addArgument("/opt");
55          // redirect stdout/stderr to pipedOutputStream
56          try (PipedOutputStream pipedOutputStream = new PipedOutputStream()) {
57              final PumpStreamHandler psh = new PumpStreamHandler(pipedOutputStream);
58              exec.setStreamHandler(psh);
59              // start an asynchronous process to enable the main thread
60              System.out.println("Preparing to execute process - commandLine=" + cl.toString());
61              final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
62              exec.execute(cl, handler);
63              System.out.println("Process spun off successfully - process=" + cl.getExecutable());
64              try (PipedInputStream pis = new PipedInputStream(pipedOutputStream)) {
65                  while (pis.read() >= 0) {
66  //                 System.out.println("pis.available() " + pis.available());
67  //                 System.out.println("x " + x);
68                  }
69              }
70              handler.waitFor(WAIT);
71              handler.getExitValue(); // will fail if process has not finished
72          }
73      }
74  
75      /**
76       * The issue was detected when trying to capture stdout with a PipedOutputStream and then pass that to a PipedInputStream. The following code will produce
77       * the error. The reason for the error is the PipedOutputStream is not being closed correctly, causing the PipedInputStream to break.
78       *
79       * @throws Exception the test failed
80       */
81      @Test
82      @DisabledOnOs(OS.WINDOWS)
83      void testExec49Part2() throws Exception {
84          final CommandLine cl = CommandLine.parse("/bin/ls");
85          cl.addArgument("/opt");
86          // redirect only stdout to pipedOutputStream
87          try (PipedOutputStream pipedOutputStream = new PipedOutputStream()) {
88              final PumpStreamHandler psh = new PumpStreamHandler(pipedOutputStream, new ByteArrayOutputStream());
89              exec.setStreamHandler(psh);
90              // start an asynchronous process to enable the main thread
91              System.out.println("Preparing to execute process - commandLine=" + cl.toString());
92              final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
93              exec.execute(cl, handler);
94              System.out.println("Process spun off successfully - process=" + cl.getExecutable());
95              try (PipedInputStream pis = new PipedInputStream(pipedOutputStream)) {
96                  while (pis.read() >= 0) {
97  //                 System.out.println("pis.available() " + pis.available());
98  //                 System.out.println("x " + x);
99                  }
100             }
101             handler.waitFor(WAIT);
102             handler.getExitValue(); // will fail if process has not finished
103         }
104     }
105 
106 }