View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.exec.issues;
19  
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  import static org.junit.jupiter.api.Assumptions.assumeFalse;
23  import static org.junit.jupiter.api.Assumptions.assumeTrue;
24  
25  import java.io.File;
26  import java.util.concurrent.TimeUnit;
27  
28  import org.apache.commons.exec.AbstractExecTest;
29  import org.apache.commons.exec.CommandLine;
30  import org.apache.commons.exec.DefaultExecutor;
31  import org.apache.commons.exec.ExecuteException;
32  import org.apache.commons.exec.ExecuteWatchdog;
33  import org.apache.commons.exec.PumpStreamHandler;
34  import org.junit.jupiter.api.Test;
35  import org.junit.jupiter.api.Timeout;
36  import org.junit.jupiter.api.condition.DisabledOnOs;
37  import org.junit.jupiter.api.condition.EnabledOnOs;
38  
39  /**
40   * Test to show that watchdog can destroy 'sudo' and 'sleep'.
41   *
42   * @see <a href="https://issues.apache.org/jira/browse/EXEC-65">EXEC-65</a>
43   */
44  public class Exec65Test extends AbstractExecTest {
45  
46      /**
47       * This test currently only works for macOS X
48       * <ul>
49       * <li>Linux hangs on the process stream while the process is finished</li>
50       * <li>Windows seems to have similar problems</li>
51       * </ul>
52       */
53      @Test
54      // TODO: Fix test for Windows & Linux
55      @EnabledOnOs(value = org.junit.jupiter.api.condition.OS.MAC)
56      @Timeout(value = TEST_TIMEOUT, unit = TimeUnit.MILLISECONDS)
57      public void testExec65WithSleepUsingShellScript() throws Exception {
58          final DefaultExecutor executor = DefaultExecutor.builder().get();
59          executor.setStreamHandler(new PumpStreamHandler(System.out, System.err));
60          executor.setWatchdog(new ExecuteWatchdog(WATCHDOG_TIMEOUT));
61          final CommandLine command = new CommandLine(resolveTestScript("sleep"));
62  
63          assertThrows(ExecuteException.class, () -> executor.execute(command));
64      }
65  
66      /**
67       * This is the original code snippet from the JIRA to show that killing the process actually works with JDK only but it does not re-direct any streams.
68       */
69      @Test
70      @Timeout(value = TEST_TIMEOUT, unit = TimeUnit.MILLISECONDS)
71      public void testExec65WithSleepUsingShellScriptAndJDKOnly() throws Exception {
72  
73          final Process process = Runtime.getRuntime().exec(resolveTestScript("sleep").getAbsolutePath());
74          Thread.sleep(WATCHDOG_TIMEOUT);
75  
76          process.destroy();
77  
78          process.waitFor();
79  
80          assertTrue(process.exitValue() != 0);
81      }
82  
83      /**
84       * Please note that this tests make assumptions about the environment. It assumes that user "root" exists and that the current user is not a "sudoer"
85       * already (thereby requiring a password).
86       */
87      @Test
88      @DisabledOnOs(org.junit.jupiter.api.condition.OS.WINDOWS)
89      @Timeout(value = TEST_TIMEOUT, unit = TimeUnit.MILLISECONDS)
90      public void testExec65WithSudoUsingShellScript() throws Exception {
91          assumeFalse(new File(".").getAbsolutePath().contains("travis"),
92                  "Test is skipped on travis, because we have to be a sudoer to make the other tests pass.");
93          // TODO Fails on GitHub
94          assumeTrue(System.getenv("GITHUB_WORKFLOW") == null);
95  
96          final DefaultExecutor executor = DefaultExecutor.builder().get();
97          executor.setStreamHandler(new PumpStreamHandler(System.out, System.err, System.in));
98          executor.setWatchdog(new ExecuteWatchdog(WATCHDOG_TIMEOUT));
99          final CommandLine command = new CommandLine(resolveTestScript("issues", "exec-65"));
100 
101         assertThrows(ExecuteException.class, () -> executor.execute(command));
102     }
103 
104     @Test
105     @DisabledOnOs(org.junit.jupiter.api.condition.OS.WINDOWS)
106     @Timeout(value = TEST_TIMEOUT, unit = TimeUnit.MILLISECONDS)
107     public void testExec65WitSleepUsingSleepCommandDirectly() throws Exception {
108         final ExecuteWatchdog watchdog = new ExecuteWatchdog(WATCHDOG_TIMEOUT);
109         final DefaultExecutor executor = DefaultExecutor.builder().get();
110         final CommandLine command = new CommandLine("sleep");
111         command.addArgument("60");
112         executor.setStreamHandler(new PumpStreamHandler(System.out, System.err));
113         executor.setWatchdog(watchdog);
114 
115         assertThrows(ExecuteException.class, () -> executor.execute(command));
116     }
117 }