Commits

Thomas Bright committed 81b8052

STASHDEV-1957 add recursive kill tests

Comments (0)

Files changed (2)

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

 package com.atlassian.utils.process;
 
-import java.io.DataInputStream;
+import org.jvnet.winp.WinProcess;
+
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 
 public class RecursiveApp {
 
-    public static void main(String [] args) throws IOException, InterruptedException {
+    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]);
 
-        if (currentLevel < maxLevel)
-        {
+        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),Integer.toString(maxLevel),Integer.toString(timeOut)};
-            for (String s : command)
-            {
+
+            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);
+            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);
 
-            DataInputStream ls_in = new DataInputStream(
-                    child.getInputStream());
-            String ls_str;
 
+            BufferedReader childOutputReader = new BufferedReader(
+                    new InputStreamReader(child.getInputStream()));
+            String line;
 
-            while ((ls_str = ls_in.readLine()) != null) {
-                System.out.println(ls_str);
+
+            while ((line = childOutputReader.readLine()) != null) {
+                System.out.println(line);
             }
 
             child.waitFor();
-        }
-        else
-        {
+        } else {
             long end = System.currentTimeMillis() + (timeOut * 1000);
-            while ( System.currentTimeMillis()  < end)
-            {
+            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

 import org.junit.Assume;
 import org.junit.Test;
 import org.jvnet.winp.WinProcess;
-import org.jvnet.winp.WinpException;
 
+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
+    @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(100000)};
+        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(3000);
-        settings.setProcessHandler(new StringProcessHandler());
+        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();
-        Thread.sleep(1000);//give it some time to start up
-        {
-            int count = getRecursiveAppCount();
-            Assert.assertEquals("Initial depth ", 6, count);    //one for command, one for java
+        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) {
         }
 
-        proc.finish();
-        //sleep and let process die/be killed
-        long end = System.currentTimeMillis() + 3000;
-        while (System.currentTimeMillis() < end) {
-            try {
-                Thread.sleep(1500);
-            } catch (InterruptedException e) {
-            }
-        }
-        {
-            int count = getRecursiveAppCount();
-            Assert.assertEquals("Final depth ", 0, count);
-        }
+        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() {
+    private int getRecursiveAppCount(List<Integer> pids) {
         int count = 0;
         for (WinProcess process : WinProcess.all()) {
-            String commandLine = null;
-            try {
-                commandLine = process.getCommandLine();
-            } catch (WinpException e) {
-                //can't open all the processes
+
+            if (pids.contains(process.getPid())) {
+                count++;
             }
 
-            if (commandLine != null) {
-                if (!commandLine.contains("cmd") && commandLine.contains("com.atlassian.utils.process.RecursiveApp")) {
-                    count++;
-                }
-            }
         }
         return count;
     }