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 }