Thomas Bright avatar Thomas Bright committed 4557e96 Merge

Merged in atlassian/atlassian-processutils/STASHDEV-1915 (pull request #2)

Comments (0)

Files changed (5)

File contents unchanged.

src/main/java/com/atlassian/utils/process/ExternalProcessImpl.java

             if (isWindows() && exitCode != 0) {
                 try {
                     new WinProcess(process).killRecursively();
-                } catch (Exception e) {
-                    LOG.error("Failed to kill Windows process; falling back on Process.destroy()", e);
+                } catch (Throwable t) {
+                    LOG.error("Failed to kill Windows process; falling back on Process.destroy()", t);
                     process.destroy();
                 }
+
             } else {
                 process.destroy();
             }
Add a comment to this file

src/test/java/com/atlassian/utils/process/ProcessBuilderEncodingTest.java

File contents unchanged.

src/test/java/com/atlassian/utils/process/RecursiveApp.java

+package com.atlassian.utils.process;
+
+import org.jvnet.winp.WinProcess;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class RecursiveApp {
+
+    public static final String PIDPREFIX = "PID: ";
+    public static final String LEVEL_SUFFIX = " started";
+    public static final String LEVEL_END_SUFFIX = " ended";
+
+    public static String getStartMessage(int level) {
+        return level + LEVEL_SUFFIX;
+    }
+
+    public static String getEndMessage(int level) {
+        return level + LEVEL_END_SUFFIX;
+    }
+
+
+
+    public static void main(String[] args) throws IOException, InterruptedException {
+        int currentLevel = Integer.parseInt(args[0]);
+        int maxLevel = Integer.parseInt(args[1]);
+        int timeOut = Integer.parseInt(args[2]);
+
+        System.out.println(getStartMessage(currentLevel));
+
+        if (currentLevel < maxLevel) {
+            //recurse
+
+            System.out.println(currentLevel + " recursing");
+            String[] command = new String[]{"java", "com.atlassian.utils.process.RecursiveApp", Integer.toString(currentLevel + 1), Integer.toString(maxLevel), Integer.toString(timeOut)};
+            for (String s : command) {
+                System.out.print(s);
+                System.out.print(" ");
+            }
+            System.out.println();
+            ProcessBuilder builder = new ProcessBuilder().command(command);
+            builder.environment().put("CLASSPATH", System.getProperty("java.class.path"));
+            Process child = builder.start();
+
+            WinProcess childP = new WinProcess(child);
+            int pid = childP.getPid();
+            System.out.println(PIDPREFIX+pid);
+
+
+            BufferedReader childOutputReader = new BufferedReader(
+                    new InputStreamReader(child.getInputStream()));
+            String line;
+
+
+            while ((line = childOutputReader.readLine()) != null) {
+                System.out.println(line);
+            }
+
+            child.waitFor();
+        } else {
+            long end = System.currentTimeMillis() + (timeOut * 1000);
+            while (System.currentTimeMillis() < end) {
+                try {
+                    Thread.sleep(timeOut);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        System.out.println(getEndMessage(currentLevel));
+
+    }
+
+}

src/test/java/com/atlassian/utils/process/RecursiveKillTest.java

+package com.atlassian.utils.process;
+
+import junit.framework.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+import org.jvnet.winp.WinProcess;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class RecursiveKillTest {
+
+
+    @Test(timeout = 10 * 1000)
+    public void testSimpleRecursiveKill() throws InterruptedException {
+
+        //we can only live on windows...
+        Assume.assumeTrue(System.getProperty("os.name").toLowerCase().indexOf("win") != -1);
+
+        ExternalProcessSettings settings = new ExternalProcessSettings();
+        String[] command = new String[]{"java", "com.atlassian.utils.process.RecursiveApp", Integer.toString(0), Integer.toString(5), Integer.toString(8)};
+        settings.setCommand(Arrays.asList(command));
+        settings.getEnvironment().put("CLASSPATH", System.getProperty("java.class.path"));
+        settings.setExecutionTimeout(5000);
+        StringProcessHandler stringHandler = new StringProcessHandler();
+        final List<Integer> pids = new ArrayList<Integer>();
+        final List<Integer> levels = new ArrayList<Integer>();
+        final List<Integer> ended = new ArrayList<Integer>();
+        final CountDownLatch latchForStart = new CountDownLatch(6);
+        stringHandler.setOutputHandler(new BaseOutputHandler() {
+
+            private final StringWriter writer = new StringWriter();
+
+            @Override
+            public void complete() {
+                IOUtils.closeQuietly(writer);
+            }
+
+            public String getOutput() {
+                return writer.toString();
+            }
+
+
+            public void process(InputStream output) throws ProcessException {
+                InputStreamReader reader = null;
+                try {
+                    BufferedReader childOutputReader = new BufferedReader(new InputStreamReader(output));
+                    String line;
+                    while ((line = childOutputReader.readLine()) != null) {
+                        if (line.startsWith(RecursiveApp.PIDPREFIX)) {
+                            Integer pid = Integer.parseInt(line.replace(RecursiveApp.PIDPREFIX, ""));
+                            pids.add(pid);
+                        } else if (line.endsWith(RecursiveApp.LEVEL_SUFFIX)) {
+                            latchForStart.countDown();
+                            Integer lvl = Integer.parseInt(line.replace(RecursiveApp.LEVEL_SUFFIX, ""));
+                            levels.add(lvl);
+                        } else if (line.endsWith(RecursiveApp.LEVEL_END_SUFFIX)) {
+                            Integer lvl = Integer.parseInt(line.replace(RecursiveApp.LEVEL_END_SUFFIX, ""));
+                            ended.add(lvl);
+                        }
+                        writer.write(line);
+                    }
+                } catch (InterruptedIOException e) {
+                    // This means the process was asked to stop which can be normal so we just finish
+                } catch (IOException e) {
+                    throw new ProcessException(e);
+                } finally {
+                    IOUtils.closeQuietly(reader);
+                }
+            }
+        });
+        settings.setProcessHandler(stringHandler);
+        ExternalProcess proc = ExternalProcessBuilder.getExternalProcessFactory().create(settings);
+
+        proc.start();
+        long start = System.currentTimeMillis();
+        latchForStart.await(8, TimeUnit.SECONDS);
+        Assert.assertTrue("Process startup time exceeded ", ((System.currentTimeMillis() - start) < 8000));
+        Assert.assertEquals("Initial depth ", 6, levels.size());
+
+
+        proc.cancel();
+
+        try {
+            Thread.sleep(200);
+
+        } catch (InterruptedException e) {
+        }
+
+        int count = getRecursiveAppCount(pids);
+        Assert.assertEquals("Final depth ", 0, count);
+
+        Assert.assertEquals("Assert that no processes finished naturally ", 0, ended.size());
+        String output = stringHandler.getOutput();
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(0)));
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(1)));
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(2)));
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(3)));
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(4)));
+        Assert.assertFalse("Assert that no processes finished naturally ", output.contains(RecursiveApp.getEndMessage(5)));
+
+    }
+
+    private int getRecursiveAppCount(List<Integer> pids) {
+        int count = 0;
+        for (WinProcess process : WinProcess.all()) {
+
+            if (pids.contains(process.getPid())) {
+                count++;
+            }
+
+        }
+        return count;
+    }
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.