7144861: speed up RMI activation tests
authorolagneau
Fri, 11 May 2012 14:13:29 -0700
changeset 12692 72f0847dd477
parent 12691 88de2d4d5084
child 12693 e3c056161305
7144861: speed up RMI activation tests Reviewed-by: alanb, smarks, dholmes, dmocek
jdk/test/java/rmi/activation/checkusage/CheckUsage.java
jdk/test/java/rmi/testlibrary/ActivationLibrary.java
jdk/test/java/rmi/testlibrary/JavaVM.java
jdk/test/java/rmi/testlibrary/RMID.java
jdk/test/java/rmi/testlibrary/StreamPipe.java
jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java
--- a/jdk/test/java/rmi/activation/checkusage/CheckUsage.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/java/rmi/activation/checkusage/CheckUsage.java	Fri May 11 14:13:29 2012 -0700
@@ -53,12 +53,9 @@
             rmidVM.start();
 
             // wait for registry exit
+            int rmidVMExitStatus = rmidVM.getVM().waitFor();
             System.err.println("rmid exited with status: " +
-                               rmidVM.getVM().waitFor());
-            try {
-                Thread.sleep(7000);
-            } catch (InterruptedException ie) {
-            }
+                               rmidVMExitStatus);
 
             String usage = new String(berr.toByteArray());
 
--- a/jdk/test/java/rmi/testlibrary/ActivationLibrary.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/java/rmi/testlibrary/ActivationLibrary.java	Fri May 11 14:13:29 2012 -0700
@@ -63,19 +63,30 @@
      */
     public static void deactivate(Remote remote,
                                   ActivationID id) {
-        for (int i = 0; i < 5; i ++) {
+        // We do as much as 50 deactivation trials, each separated by
+        // at least 100 milliseconds sleep time (max sleep time of 5 secs).
+        final long deactivateSleepTime = 100;
+        for (int i = 0; i < 50; i ++) {
             try {
                 if (Activatable.inactive(id) == true) {
                     mesg("inactive successful");
                     return;
                 } else {
-                    Thread.sleep(1000);
+                    mesg("inactive trial failed. Sleeping " +
+                         deactivateSleepTime +
+                         " milliseconds before next trial");
+                    Thread.sleep(deactivateSleepTime);
                 }
             } catch (InterruptedException e) {
-                continue;
+                Thread.currentThread().interrupt();
+                mesg("Thread interrupted while trying to deactivate activatable. Exiting deactivation");
+                return;
             } catch (Exception e) {
                 try {
                     // forcibly unexport the object
+                    mesg("Unexpected exception. Have to forcibly unexport the object." +
+                         " Exception was :");
+                    e.printStackTrace();
                     Activatable.unexportObject(remote, true);
                 } catch (NoSuchObjectException ex) {
                 }
@@ -99,37 +110,61 @@
      * activation system.
      */
     public static boolean rmidRunning(int port) {
-        int allowedNotReady = 10;
+        int allowedNotReady = 50;
         int connectionRefusedExceptions = 0;
 
-        for (int i = 0; i < 15 ; i++) {
+        /* We wait as much as a total of 7.5 secs trying to see Rmid running.
+         * We do this by pausing steps of 100 milliseconds (so up to 75 steps),
+         * right after trying to lookup and find RMID running in the other vm.
+         */
+        final long rmidWaitingStepTime = 100;
+        for (int i = 0; i <= 74; i++) {
 
             try {
-                Thread.sleep(500);
                 LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME);
+                mesg("Activation System available after " +
+                     (i * rmidWaitingStepTime) + " milliseconds");
                 return true;
 
             } catch (java.rmi.ConnectException e) {
+                mesg("Remote connection refused after " +
+                     (i * rmidWaitingStepTime) + " milliseconds");
+
                 // ignore connect exceptions until we decide rmid is not up
-
                 if ((connectionRefusedExceptions ++) >= allowedNotReady) {
                     return false;
                 }
 
+            } catch (java.rmi.NoSuchObjectException nsoe) {
+                /* Activation System still unavailable.
+                 * Ignore this since we are just waiting for its availibility.
+                 * Just signal unavailibility.
+                 */
+                mesg("Activation System still unavailable after more than " +
+                     (i * rmidWaitingStepTime) + " milliseconds");
+
             } catch (NotBoundException e) {
-
                 return false;
 
             } catch (Exception e) {
-                // print out other types of exceptions as an FYI.
-                // test should not fail as rmid is likely to be in an
-                // undetermined state at this point.
-
+                /* print out other types of exceptions as an FYI.
+                 * test should not fail as rmid is likely to be in an
+                 * undetermined state at this point.
+                 */
                 mesg("caught an exception trying to" +
                      " start rmid, last exception was: " +
                      e.getMessage());
                 e.printStackTrace();
             }
+
+            // Waiting for another 100 milliseconds.
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                mesg("Thread interrupted while checking if Activation System is running. Exiting check");
+                return false;
+            }
         }
         return false;
     }
--- a/jdk/test/java/rmi/testlibrary/JavaVM.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/java/rmi/testlibrary/JavaVM.java	Fri May 11 14:13:29 2012 -0700
@@ -36,7 +36,6 @@
  */
 public class JavaVM {
 
-    // need to
     protected Process vm = null;
 
     private String classname = "";
@@ -46,6 +45,10 @@
     private OutputStream errorStream = System.err;
     private String policyFileName = null;
 
+    // This is used to shorten waiting time at startup.
+    private volatile boolean started = false;
+    private boolean forcesOutput = true; // default behavior
+
     private static void mesg(Object mesg) {
         System.err.println("JAVAVM: " + mesg.toString());
     }
@@ -79,6 +82,25 @@
         this.errorStream = err;
     }
 
+    /* This constructor will instantiate a JavaVM object for which caller
+     * can ask for forcing initial version output on child vm process
+     * (if forcesVersionOutput is true), or letting the started vm behave freely
+     * (when forcesVersionOutput is false).
+     */
+    public JavaVM(String classname,
+                  String options, String args,
+                  OutputStream out, OutputStream err,
+                  boolean forcesVersionOutput) {
+        this(classname, options, args, out, err);
+        this.forcesOutput = forcesVersionOutput;
+    }
+
+
+    public void setStarted() {
+        started = true;
+    }
+
+    // Prepends passed opts array to current options
     public void addOptions(String[] opts) {
         String newOpts = "";
         for (int i = 0 ; i < opts.length ; i ++) {
@@ -87,6 +109,8 @@
         newOpts += " ";
         options = newOpts + options;
     }
+
+    // Prepends passed arguments array to current args
     public void addArguments(String[] arguments) {
         String newArgs = "";
         for (int i = 0 ; i < arguments.length ; i ++) {
@@ -127,6 +151,18 @@
 
         addOptions(new String[] { getCodeCoverageOptions() });
 
+        /*
+         * If forcesOutput is true :
+         *  We force the new starting vm to output something so that we can know
+         *  when it is effectively started by redirecting standard output through
+         *  the next StreamPipe call (the vm is considered started when a first
+         *  output has been streamed out).
+         *  We do this by prepnding a "-showversion" option in the command line.
+         */
+        if (forcesOutput) {
+            addOptions(new String[] {"-showversion"});
+        }
+
         StringTokenizer optionsTokenizer = new StringTokenizer(options);
         StringTokenizer argsTokenizer = new StringTokenizer(args);
         int optionsCount = optionsTokenizer.countTokens();
@@ -150,15 +186,43 @@
         vm = Runtime.getRuntime().exec(javaCommand);
 
         /* output from the execed process may optionally be captured. */
-        StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);
-        StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);
+        StreamPipe.plugTogether(this, vm.getInputStream(), this.outputStream);
+        StreamPipe.plugTogether(this, vm.getErrorStream(), this.errorStream);
 
         try {
-            Thread.sleep(2000);
-        } catch (Exception ignore) {
+            if (forcesOutput) {
+                // Wait distant vm to start, by using waiting time slices of 100 ms.
+                // Wait at most for 2secs, after it considers the vm to be started.
+                final long vmStartSleepTime = 100;
+                final int maxTrials = 20;
+                int numTrials = 0;
+                while (!started && numTrials < maxTrials) {
+                    numTrials++;
+                    Thread.sleep(vmStartSleepTime);
+                }
+
+                // Outputs running status of distant vm
+                String message =
+                    "after " + (numTrials * vmStartSleepTime) + " milliseconds";
+                if (started) {
+                    mesg("distant vm process running, " + message);
+                }
+                else {
+                    mesg("unknown running status of distant vm process, " + message);
+                }
+            }
+            else {
+                // Since we have no way to know if the distant vm is started,
+                // we just consider the vm to be started after a 2secs waiting time.
+                Thread.sleep(2000);
+                mesg("distant vm considered to be started after a waiting time of 2 secs");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            mesg("Thread interrupted while checking if distant vm is started. Giving up check.");
+            mesg("Distant vm state unknown");
+            return;
         }
-
-        mesg("finished starting vm.");
     }
 
     public void destroy() {
--- a/jdk/test/java/rmi/testlibrary/RMID.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/java/rmi/testlibrary/RMID.java	Fri May 11 14:13:29 2012 -0700
@@ -218,20 +218,30 @@
         } catch (NumberFormatException ignore) {}
         waitTime = waitTime * slopFactor;
 
-        // give rmid time to come up
+        // We check several times (as many as provides passed waitTime) to
+        // see if Rmid is currently running. Waiting steps last 100 msecs.
+        final long rmidStartSleepTime = 100;
         do {
+            // Sleeping for another rmidStartSleepTime time slice.
             try {
-                Thread.sleep(Math.min(waitTime, 10000));
+                Thread.sleep(Math.min(waitTime, rmidStartSleepTime));
             } catch (InterruptedException ie) {
                 Thread.currentThread().interrupt();
+                mesg("Thread interrupted while checking for start of Activation System. Giving up check.");
+                mesg("Activation System state unknown");
+                return;
             }
-            waitTime -= 10000;
+            waitTime -= rmidStartSleepTime;
 
-            // is rmid present?
+            // Checking if rmid is present
             if (ActivationLibrary.rmidRunning(port)) {
                 mesg("finished starting rmid.");
                 return;
             }
+            else {
+                mesg("rmid still not started");
+            }
+
         } while (waitTime > 0);
         TestLibrary.bomb("start rmid failed... giving up", null);
     }
@@ -264,6 +274,8 @@
                     port +
                     "/java.rmi.activation.ActivationSystem");
                 mesg("obtained a reference to the activation system");
+            } catch (RemoteException re) {
+                mesg("could not contact registry while trying to shutdown activation system");
             } catch (java.net.MalformedURLException mue) {
             }
 
@@ -272,19 +284,14 @@
             }
             system.shutdown();
 
+        } catch (RemoteException re) {
+            mesg("shutting down the activation daemon failed");
         } catch (Exception e) {
             mesg("caught exception trying to shutdown rmid");
             mesg(e.getMessage());
             e.printStackTrace();
         }
 
-        try {
-            // wait for the shutdown to happen
-            Thread.sleep(5000);
-        } catch (InterruptedException ie) {
-            Thread.currentThread().interrupt();
-        }
-
         mesg("testlibrary finished shutting down rmid");
     }
 
@@ -301,18 +308,47 @@
 
         if (vm != null) {
             try {
-                // destroy rmid if it is still running...
-                try {
-                    vm.exitValue();
-                    mesg("rmid exited on shutdown request");
-                } catch (IllegalThreadStateException illegal) {
-                    mesg("Had to destroy RMID's process " +
-                         "using Process.destroy()");
+                /* Waiting for distant RMID process to shutdown.
+                 * Waiting is bounded at a hardcoded max of 60 secs (1 min).
+                 * Waiting by steps of 200 msecs, thus at most 300 such attempts
+                 * for termination of distant RMID process. If process is not
+                 * known to be terminated properly after that time,
+                 * we give up for a gracefull termination, and thus go for
+                 * forcibly destroying the process.
+                 */
+                boolean vmEnded = false;
+                int waitingTrials = 0;
+                final int maxTrials = 300;
+                final long vmProcessEndWaitInterval = 200;
+                int vmExitValue;
+                do {
+                    try {
+                        Thread.sleep(vmProcessEndWaitInterval);
+                        waitingTrials++;
+                        vmExitValue = vm.exitValue();
+                        mesg("rmid exited on shutdown request");
+                        vmEnded = true;
+                    } catch (IllegalThreadStateException illegal) {
+                        mesg("RMID's process still not terminated after more than " +
+                             (waitingTrials * vmProcessEndWaitInterval) + " milliseconds");
+                    }
+                }
+                while (!vmEnded &&
+                       (waitingTrials < maxTrials));
+
+                if (waitingTrials >= maxTrials) {
+                    mesg("RMID's process still not terminated after more than " +
+                         (waitingTrials * vmProcessEndWaitInterval) + " milliseconds." +
+                         "Givinp up gracefull termination...");
+                    mesg("destroying RMID's process using Process.destroy()");
                     super.destroy();
                 }
 
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                mesg("Thread interrupted while checking for termination of distant rmid vm. Giving up check.");
             } catch (Exception e) {
-                mesg("caught exception trying to destroy rmid: " +
+                mesg("caught unexpected exception trying to destroy rmid: " +
                      e.getMessage());
                 e.printStackTrace();
             }
--- a/jdk/test/java/rmi/testlibrary/StreamPipe.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/java/rmi/testlibrary/StreamPipe.java	Fri May 11 14:13:29 2012 -0700
@@ -35,46 +35,89 @@
     private InputStream in;
     private OutputStream out;
     private String preamble;
+    private JavaVM javaVM;
     private static Object lock = new Object();
     private static int count = 0;
 
-    public StreamPipe(InputStream in, OutputStream out, String name) {
+
+    /* StreamPipe constructor : should only be called by plugTogether() method !!
+     * If passed vm is not null :
+     * -  This is StreamPipe usage when streams to pipe come from a given
+     *    vm (JavaVM) process (the vm process must be started with a prefixed
+     *    "-showversion" option to be able to determine as soon as possible when
+     *    the vm process is started through the redirection of the streams).
+     *    There must be a close connection between the StreamPipe instance and
+     *    the JavaVM object on which a start() call has been done.
+     *    run() method will flag distant JavaVM as started.
+     * If passed vm is null :
+     * -  We don't have control on the process which we want to redirect the passed
+     *    streams.
+     *    run() method will ignore distant process.
+     */
+    private StreamPipe(JavaVM vm, InputStream in, OutputStream out, String name) {
         super(name);
         this.in  = in;
         this.out = out;
         this.preamble = "# ";
+        this.javaVM = vm;
     }
 
+    // Install redirection of passed InputStream and OutputStream from passed JavaVM
+    // to this vm standard output and input streams.
+    public static void plugTogether(JavaVM vm, InputStream in, OutputStream out) {
+        String name = null;
+
+        synchronized (lock) {
+            name = "TestLibrary: StreamPipe-" + (count ++ );
+        }
+
+        Thread pipe = new StreamPipe(vm, in, out, name);
+        pipe.setDaemon(true);
+        pipe.start();
+    }
+
+    /* Redirects the InputStream and OutputStream passed by caller to this
+     * vm standard output and input streams.
+     * (we just have to use fully parametered plugTogether() call with a null
+     *  JavaVM input to do this).
+     */
+    public static void plugTogether(InputStream in, OutputStream out) {
+        plugTogether(null, in, out);
+    }
+
+    // Starts redirection of streams.
     public void run() {
         BufferedReader r = new BufferedReader(new InputStreamReader(in), 1);
         BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out));
         byte[] buf = new byte[256];
-        boolean bol = true;     // beginning-of-line
-        int count;
 
         try {
             String line;
-            while ((line = r.readLine()) != null) {
+
+            /* This is to check that the distant vm has started,
+             * if such a vm has been provided at construction :
+             * - As soon as we can read something from r BufferedReader,
+             *   that means the distant vm is already started.
+             * Thus we signal associated JavaVM object that it is now started.
+             */
+            if (((line = r.readLine()) != null) &&
+                (javaVM != null)) {
+                javaVM.setStarted();
+            }
+
+            // Redirects r on w.
+            while (line != null) {
                 w.write(preamble);
                 w.write(line);
                 w.newLine();
                 w.flush();
+                line = r.readLine();
             }
+
         } catch (IOException e) {
             System.err.println("*** IOException in StreamPipe.run:");
             e.printStackTrace();
         }
     }
 
-    public static void plugTogether(InputStream in, OutputStream out) {
-        String name = null;
-
-        synchronized (lock) {
-            name = "TestLibrary: StreamPipe-" + (count ++ );
-        }
-
-        Thread pipe = new StreamPipe(in, out, name);
-        pipe.setDaemon(true);
-        pipe.start();
-    }
 }
--- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Fri May 11 12:53:03 2012 -0700
+++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Fri May 11 14:13:29 2012 -0700
@@ -60,9 +60,12 @@
             File.separatorChar + "logging.properties";
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ByteArrayOutputStream err = new ByteArrayOutputStream();
+
+        // We instantiate a JavaVM that should not produce any console output
+        // (neither on standard output, nor on standard err streams).
         JavaVM vm = new JavaVM(DoRMIStuff.class.getName(),
             "-Djava.util.logging.config.file=" + loggingPropertiesFile,
-                               "", out, err);
+                               "", out, err, false);
         vm.start();
         vm.getVM().waitFor();