1 /*
   2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.*;
  25 import java.util.concurrent.TimeUnit;
  26 
  27 public class ProcessKillTest implements Runnable {
  28 
  29     private Process p;
  30     private static enum OS {
  31         WINDOWS, LINUX, SOLARIS, MAC
  32     }
  33     private static OS currentOS;
  34 
  35     public ProcessKillTest() throws Exception {
  36         String osName = System.getProperty("os.name");
  37         if(osName.toLowerCase().indexOf("win") == 0)
  38             currentOS = OS.WINDOWS;
  39         else if(osName.toLowerCase().indexOf("lin") == 0)
  40             currentOS = OS.LINUX;
  41         else if(osName.contains("OS X"))
  42             currentOS = OS.MAC;
  43     
  44         ProcessBuilder bldr;
  45         if (currentOS == OS.WINDOWS)
  46             bldr = new ProcessBuilder("ping", "-t", "127.0.0.1");
  47         else
  48             bldr = new ProcessBuilder("./ProcessTrap.sh");
  49         bldr.redirectErrorStream(true);
  50         bldr.directory(new File("."));
  51         p = bldr.start();
  52     }
  53 
  54     public Process getProc() {
  55         return p;
  56     }
  57 
  58     public void killProc(boolean force) throws Exception {
  59         if(force) {
  60             p.destroyForcibly().waitFor();
  61             // System.out.println(p.exitValue());
  62             if ((currentOS == OS.SOLARIS && p.exitValue() != 9) ||
  63                 ((currentOS == OS.LINUX || currentOS == OS.MAC) 
  64                  && p.exitValue() != 137))
  65                 throw new RuntimeException("Test failed: wrong exit value");
  66         } else {
  67             p.destroy();
  68         }
  69     }
  70 
  71     public boolean isAlive() {
  72         return p.isAlive();
  73     }
  74 
  75     public void run() {
  76         try {
  77             String line;
  78             BufferedReader is =
  79                 new BufferedReader(new InputStreamReader(p.getInputStream()));
  80             while ((line = is.readLine()) != null)
  81                 System.err.println("ProcessTrap: " + line);
  82         } catch(IOException e) {
  83             if (!e.getMessage().equals("Stream closed")) {
  84                 throw new RuntimeException(e);
  85             }
  86         }
  87     }
  88 
  89     public static void runTest(ProcessKillTest test) throws Exception {
  90         TimeUnit nanos = TimeUnit.NANOSECONDS;
  91     
  92         // this tests that the script is trapping the SIGTERM properly
  93         // and that it doesn't cause the process to terminate.
  94         // since windows would kill the process on a destroy(false) 
  95         // we don't perform this test.
  96         // On Mac, it appears that when we close the processes streams
  97         // after a destroy() call, the process terminates with a 
  98         // SIGPIPE even if it was trapping the SIGTERM, so as with
  99         // windows, we skip this trap test.
 100         if(currentOS == OS.SOLARIS || currentOS == OS.LINUX)
 101             test.killProc(false);
 102 
 103         long start = System.nanoTime();
 104         if (!test.isAlive() ||
 105             test.getProc().waitFor(0, TimeUnit.MILLISECONDS)) {
 106             throw new RuntimeException(
 107                 "Test failed: Process exited prematurely");
 108         }
 109         long end = System.nanoTime();
 110         if(nanos.toMillis(end - start) > 10)
 111             throw new RuntimeException(
 112                 "Test failed: waitFor took too long");
 113 
 114         start = System.nanoTime();
 115         test.getProc().waitFor(3000, TimeUnit.MILLISECONDS);
 116         end = System.nanoTime();
 117         if(nanos.toMillis(end - start) < 3000)
 118             throw new RuntimeException(
 119                 "Test failed: waitFor didn't take long enough");
 120         
 121         if(currentOS == OS.WINDOWS)
 122             test.killProc(false); // make sure killProc(false) works on win
 123         else
 124             test.killProc(true);  // test destroyForcibly(true);
 125         test.getProc().waitFor();
 126         
 127         start = System.nanoTime();
 128         if (test.isAlive() || 
 129             !test.getProc().waitFor(0, TimeUnit.MILLISECONDS)) {
 130             throw new RuntimeException(
 131                 "Test failed: Process hasn't been killed, please terminate " +
 132                 test.getProc().toString() + " manually");
 133         }
 134         end = System.nanoTime();
 135         if(nanos.toMillis(end - start) > 10)
 136             throw new RuntimeException(
 137                 "Test failed: waitFor took too long with a timeout of 0");
 138         
 139         
 140         start = System.nanoTime();
 141         test.getProc().waitFor(100, TimeUnit.MILLISECONDS);
 142         end = System.nanoTime();
 143         if(nanos.toMillis(end - start) > 10)
 144             throw new RuntimeException(
 145                 "Test failed: waitFor took too long on dead process");
 146         
 147         System.out.println("Test passed");
 148     }
 149 
 150     public static void main(String args[]) throws Exception {
 151         ProcessKillTest test = new ProcessKillTest();
 152         new Thread(test).start();
 153         Thread.sleep(1000);
 154         runTest(test);
 155     }
 156 }