jdk/test/tools/launcher/Arrrghs.java
changeset 2 90ce3da70b43
child 399 bcc2354430ff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/Arrrghs.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,206 @@
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+public class Arrrghs{
+
+    /**
+     * A group of tests to ensure that arguments are passed correctly to
+     * a child java process upon a re-exec, this typically happens when
+     * a version other than the one being executed is requested by the user.
+     *
+     * History: these set of tests  were part of Arrrghs.sh. The MKS shell
+     * implementations are notoriously buggy. Implementing these tests purely
+     * in Java is not only portable but also robust.
+     *
+     */
+
+    /* Do not instantiate */
+    private Arrrghs() {}
+
+    static String javaCmd;
+
+    // The version string to force a re-exec
+    final static String VersionStr = "-version:1.1+";
+
+    // The Cookie or the pattern we match in the debug output.
+    final static String Cookie = "ReExec Args: ";
+
+    private static boolean _debug = Boolean.getBoolean("Arrrghs.Debug");
+    private static boolean isWindows = System.getProperty("os.name", "unknown").startsWith("Windows");
+    private static int exitValue = 0;
+
+    private static void doUsage(String message) {
+        if (message != null) System.out.println("Error: " + message);
+        System.out.println("Usage: Arrrghs path_to_java");
+        System.exit(1);
+    }
+
+    /*
+     * SIGH, On Windows all strings are quoted, we need to unwrap it
+     */
+    private static String removeExtraQuotes(String in) {
+        if (isWindows) {
+            // Trim the string and remove the enclosed quotes if any.
+            in = in.trim();
+            if (in.startsWith("\"") && in.endsWith("\"")) {
+                return in.substring(1, in.length()-1);
+            }
+        }
+        return in;
+    }
+
+
+    /*
+     * This method detects the cookie in the output stream of the process.
+     */
+    private static boolean detectCookie(InputStream istream, String expectedArguments) throws IOException {
+        BufferedReader rd = new BufferedReader(new InputStreamReader(istream));
+        boolean retval = false;
+
+        String in = rd.readLine();
+        while (in != null) {
+            if (_debug) System.out.println(in);
+            if (in.startsWith(Cookie)) {
+                String detectedArgument = removeExtraQuotes(in.substring(Cookie.length()));
+                if (expectedArguments.equals(detectedArgument)) {
+                    retval = true;
+                } else {
+                    System.out.println("Error: Expected Arguments\t:'" + expectedArguments + "'");
+                    System.out.println(" Detected Arguments\t:'" + detectedArgument + "'");
+                }
+                // Return the value asap if not in debug mode.
+                if (!_debug) {
+                    rd.close();
+                    istream.close();
+                    return retval;
+                }
+            }
+            in = rd.readLine();
+        }
+        return retval;
+    }
+
+
+
+    private static boolean doExec0(ProcessBuilder pb, String expectedArguments) {
+        boolean retval = false;
+        try {
+            pb.redirectErrorStream(_debug);
+            Process p = pb.start();
+            retval = detectCookie(p.getInputStream(), expectedArguments);
+            p.waitFor();
+            p.destroy();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            throw new RuntimeException(ex.getMessage());
+        }
+        return retval;
+    }
+
+    /**
+     * This method return true  if the expected and detected arguments are the same.
+     * Quoting could cause dissimilar testArguments and expected arguments.
+     */
+    static boolean doExec(String testArguments, String expectedPattern) {
+        ProcessBuilder pb = new ProcessBuilder(javaCmd, VersionStr, testArguments);
+
+        Map<String, String> env = pb.environment();
+        env.put("_JAVA_LAUNCHER_DEBUG", "true");
+        return doExec0(pb, testArguments);
+    }
+
+    /**
+     * A convenience method for identical test pattern and expected arguments
+     */
+    static boolean doExec(String testPattern) {
+        return doExec(testPattern, testPattern);
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        if (args.length < 1 && args[0] == null) {
+            doUsage("Invalid number of arguments");
+        }
+
+        javaCmd = args[0];
+
+        if (!new File(javaCmd).canExecute()) {
+            if (isWindows && new File(javaCmd + ".exe").canExecute()) {
+                javaCmd = javaCmd + ".exe";
+            } else {
+                doUsage("The java executable must exist");
+            }
+        }
+
+
+        if (_debug) System.out.println("Starting Arrrghs tests");
+        // Basic test
+        if (!doExec("-a -b -c -d")) exitValue++;
+
+        // Basic test with many spaces
+        if (!doExec("-a    -b      -c       -d")) exitValue++;
+
+        // Quoted whitespace does matter ?
+        if (!doExec("-a \"\"-b      -c\"\" -d")) exitValue++;
+
+        // Escaped quotes outside of quotes as literals
+        if (!doExec("-a \\\"-b -c\\\" -d")) exitValue++;
+
+        // Check for escaped quotes inside of quotes as literal
+        if (!doExec("-a \"-b \\\"stuff\\\"\" -c -d")) exitValue++;
+
+        // A quote preceeded by an odd number of slashes is a literal quote
+        if (!doExec("-a -b\\\\\\\" -c -d")) exitValue++;
+
+        // A quote preceeded by an even number of slashes is a literal quote
+        // see 6214916.
+        if (!doExec("-a -b\\\\\\\\\" -c -d")) exitValue++;
+
+        // Make sure that whitespace doesn't interfere with the removal of the
+        // appropriate tokens. (space-tab-space preceeds -jre-restict-search).
+        if (!doExec("-a -b  \t -jre-restrict-search -c -d","-a -b -c -d")) exitValue++;
+
+        // Make sure that the mJRE tokens being stripped, aren't stripped if
+        // they happen to appear as arguments to the main class.
+        if (!doExec("foo -version:1.1+")) exitValue++;
+
+        System.out.println("Completed Arrrghs arguments quoting/matching tests with " + exitValue + " errors");
+        System.exit(exitValue);
+    }
+
+}