jdk/test/tools/launcher/Arrrghs.java
changeset 1323 e14a3b3536cd
parent 399 bcc2354430ff
child 1329 ce13b59a8401
equal deleted inserted replaced
1322:d038148778cc 1323:e14a3b3536cd
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    21  * have any questions.
    21  * have any questions.
    22  */
    22  */
    23 
    23 
       
    24 /**
       
    25  * @test
       
    26  * @compile  -XDignore.symbol.file Arrrghs.java TestHelper.java
       
    27  * @bug 5030233 6214916 6356475 6571029 6684582
       
    28  * @run main Arrrghs
       
    29  * @summary Argument parsing validation.
       
    30  */
       
    31 
    24 import java.io.BufferedReader;
    32 import java.io.BufferedReader;
    25 import java.io.File;
    33 import java.io.File;
       
    34 import java.io.FileNotFoundException;
    26 import java.io.IOException;
    35 import java.io.IOException;
    27 import java.io.InputStream;
    36 import java.io.InputStream;
    28 import java.io.InputStreamReader;
    37 import java.io.InputStreamReader;
    29 import java.util.ArrayList;
       
    30 import java.util.Collection;
       
    31 import java.util.Collections;
       
    32 import java.util.List;
       
    33 import java.util.Map;
    38 import java.util.Map;
    34 import java.util.StringTokenizer;
       
    35 
    39 
    36 public class Arrrghs {
    40 public class Arrrghs {
    37 
    41     private Arrrghs(){}
    38     /**
    42     /**
       
    43      * This class provides various tests for arguments processing.
    39      * A group of tests to ensure that arguments are passed correctly to
    44      * A group of tests to ensure that arguments are passed correctly to
    40      * a child java process upon a re-exec, this typically happens when
    45      * a child java process upon a re-exec, this typically happens when
    41      * a version other than the one being executed is requested by the user.
    46      * a version other than the one being executed is requested by the user.
    42      *
    47      *
    43      * History: these set of tests  were part of Arrrghs.sh. The MKS shell
    48      * History: these set of tests  were part of Arrrghs.sh. The MKS shell
    44      * implementations are notoriously buggy. Implementing these tests purely
    49      * implementations were notoriously buggy. Implementing these tests purely
    45      * in Java is not only portable but also robust.
    50      * in Java is not only portable but also robust.
    46      *
    51      *
    47      */
    52      */
    48 
    53 
    49     /* Do not instantiate */
       
    50     private Arrrghs() {}
       
    51 
       
    52     static String javaCmd;
       
    53 
       
    54     // The version string to force a re-exec
    54     // The version string to force a re-exec
    55     final static String VersionStr = "-version:1.1+";
    55     final static String VersionStr = "-version:1.1+";
    56 
    56 
    57     // The Cookie or the pattern we match in the debug output.
    57     // The Cookie or the pattern we match in the debug output.
    58     final static String Cookie = "ReExec Args: ";
    58     final static String Cookie = "ReExec Args: ";
    59 
    59 
    60     private static boolean _debug = Boolean.getBoolean("Arrrghs.Debug");
       
    61     private static boolean isWindows = System.getProperty("os.name", "unknown").startsWith("Windows");
       
    62     private static int exitValue = 0;
       
    63 
       
    64     private static void doUsage(String message) {
       
    65         if (message != null) System.out.println("Error: " + message);
       
    66         System.out.println("Usage: Arrrghs path_to_java");
       
    67         System.exit(1);
       
    68     }
       
    69 
       
    70     /*
    60     /*
    71      * SIGH, On Windows all strings are quoted, we need to unwrap it
    61      * SIGH, On Windows all strings are quoted, we need to unwrap it
    72      */
    62      */
    73     private static String removeExtraQuotes(String in) {
    63     private static String removeExtraQuotes(String in) {
    74         if (isWindows) {
    64         if (TestHelper.isWindows) {
    75             // Trim the string and remove the enclosed quotes if any.
    65             // Trim the string and remove the enclosed quotes if any.
    76             in = in.trim();
    66             in = in.trim();
    77             if (in.startsWith("\"") && in.endsWith("\"")) {
    67             if (in.startsWith("\"") && in.endsWith("\"")) {
    78                 return in.substring(1, in.length()-1);
    68                 return in.substring(1, in.length()-1);
    79             }
    69             }
    80         }
    70         }
    81         return in;
    71         return in;
    82     }
    72     }
    83 
    73 
    84 
       
    85     /*
    74     /*
    86      * This method detects the cookie in the output stream of the process.
    75      * This method detects the cookie in the output stream of the process.
    87      */
    76      */
    88     private static boolean detectCookie(InputStream istream, String expectedArguments) throws IOException {
    77     private static boolean detectCookie(InputStream istream,
       
    78             String expectedArguments) throws IOException {
    89         BufferedReader rd = new BufferedReader(new InputStreamReader(istream));
    79         BufferedReader rd = new BufferedReader(new InputStreamReader(istream));
    90         boolean retval = false;
    80         boolean retval = false;
    91 
    81 
    92         String in = rd.readLine();
    82         String in = rd.readLine();
    93         while (in != null) {
    83         while (in != null) {
    94             if (_debug) System.out.println(in);
    84             if (TestHelper.debug) System.out.println(in);
    95             if (in.startsWith(Cookie)) {
    85             if (in.startsWith(Cookie)) {
    96                 String detectedArgument = removeExtraQuotes(in.substring(Cookie.length()));
    86                 String detectedArgument = removeExtraQuotes(in.substring(Cookie.length()));
    97                 if (expectedArguments.equals(detectedArgument)) {
    87                 if (expectedArguments.equals(detectedArgument)) {
    98                     retval = true;
    88                     retval = true;
    99                 } else {
    89                 } else {
   100                     System.out.println("Error: Expected Arguments\t:'" + expectedArguments + "'");
    90                     System.out.println("Error: Expected Arguments\t:'" +
   101                     System.out.println(" Detected Arguments\t:'" + detectedArgument + "'");
    91                             expectedArguments + "'");
       
    92                     System.out.println(" Detected Arguments\t:'" +
       
    93                             detectedArgument + "'");
   102                 }
    94                 }
   103                 // Return the value asap if not in debug mode.
    95                 // Return the value asap if not in debug mode.
   104                 if (!_debug) {
    96                 if (!TestHelper.debug) {
   105                     rd.close();
    97                     rd.close();
   106                     istream.close();
    98                     istream.close();
   107                     return retval;
    99                     return retval;
   108                 }
   100                 }
   109             }
   101             }
   110             in = rd.readLine();
   102             in = rd.readLine();
   111         }
   103         }
   112         return retval;
   104         return retval;
   113     }
   105     }
   114 
   106 
   115     private static boolean doExec0(ProcessBuilder pb, String expectedArguments) {
   107     private static boolean doTest0(ProcessBuilder pb, String expectedArguments) {
   116         boolean retval = false;
   108         boolean retval = false;
   117         try {
   109         try {
   118             pb.redirectErrorStream(true);
   110             pb.redirectErrorStream(true);
   119             Process p = pb.start();
   111             Process p = pb.start();
   120             retval = detectCookie(p.getInputStream(), expectedArguments);
   112             retval = detectCookie(p.getInputStream(), expectedArguments);
   129 
   121 
   130     /**
   122     /**
   131      * This method return true  if the expected and detected arguments are the same.
   123      * This method return true  if the expected and detected arguments are the same.
   132      * Quoting could cause dissimilar testArguments and expected arguments.
   124      * Quoting could cause dissimilar testArguments and expected arguments.
   133      */
   125      */
   134     static boolean doExec(String testArguments, String expectedPattern) {
   126     static int doTest(String testArguments, String expectedPattern) {
   135         ProcessBuilder pb = new ProcessBuilder(javaCmd, VersionStr, testArguments);
   127         ProcessBuilder pb = new ProcessBuilder(TestHelper.javaCmd,
       
   128                 VersionStr, testArguments);
   136 
   129 
   137         Map<String, String> env = pb.environment();
   130         Map<String, String> env = pb.environment();
   138         env.put("_JAVA_LAUNCHER_DEBUG", "true");
   131         env.put("_JAVA_LAUNCHER_DEBUG", "true");
   139         return doExec0(pb, testArguments);
   132         return doTest0(pb, testArguments) ? 0 : 1;
   140     }
   133     }
   141 
   134 
   142     /**
   135     /**
   143      * A convenience method for identical test pattern and expected arguments
   136      * A convenience method for identical test pattern and expected arguments
   144      */
   137      */
   145     static boolean doExec(String testPattern) {
   138     static int doTest(String testPattern) {
   146         return doExec(testPattern, testPattern);
   139         return doTest(testPattern, testPattern);
       
   140     }
       
   141 
       
   142     static void quoteParsingTests() {
       
   143         /*
       
   144          * Tests for 6214916
       
   145          * These tests require that a JVM (any JVM) be installed in the system registry.
       
   146          * If none is installed, skip this test.
       
   147          */
       
   148         TestHelper.TestResult tr =
       
   149                 TestHelper.doExec(TestHelper.javaCmd, VersionStr, "-version");
       
   150         if (!tr.isOK()) {
       
   151             System.err.println("Warning:Argument Passing Tests were skipped, " +
       
   152                     "no java found in system registry.");
       
   153             return;
       
   154         }
       
   155 
       
   156         // Basic test
       
   157         TestHelper.testExitValue += doTest("-a -b -c -d");
       
   158 
       
   159         // Basic test with many spaces
       
   160         TestHelper.testExitValue += doTest("-a    -b      -c       -d");
       
   161 
       
   162         // Quoted whitespace does matter ?
       
   163         TestHelper.testExitValue += doTest("-a \"\"-b      -c\"\" -d");
       
   164 
       
   165 
       
   166         // Escaped quotes outside of quotes as literals
       
   167         TestHelper.testExitValue += doTest("-a \\\"-b -c\\\" -d");
       
   168 
       
   169         // Check for escaped quotes inside of quotes as literal
       
   170         TestHelper.testExitValue += doTest("-a \"-b \\\"stuff\\\"\" -c -d");
       
   171 
       
   172         // A quote preceeded by an odd number of slashes is a literal quote
       
   173         TestHelper.testExitValue += doTest("-a -b\\\\\\\" -c -d");
       
   174 
       
   175         // A quote preceeded by an even number of slashes is a literal quote
       
   176         // see 6214916.
       
   177         TestHelper.testExitValue += doTest("-a -b\\\\\\\\\" -c -d");
       
   178 
       
   179         // Make sure that whitespace doesn't interfere with the removal of the
       
   180         // appropriate tokens. (space-tab-space preceeds -jre-restict-search).
       
   181         TestHelper.testExitValue += doTest("-a -b  \t -jre-restrict-search -c -d","-a -b -c -d");
       
   182 
       
   183         // Make sure that the mJRE tokens being stripped, aren't stripped if
       
   184         // they happen to appear as arguments to the main class.
       
   185         TestHelper.testExitValue += doTest("foo -version:1.1+");
       
   186 
       
   187         System.out.println("Completed arguments quoting tests with " +
       
   188                 TestHelper.testExitValue + " errors");
       
   189     }
       
   190 
       
   191     /*
       
   192      * These tests are usually run on non-existent targets to check error results
       
   193      */
       
   194     static void runBasicErrorMessageTests() {
       
   195         // Tests for 5030233
       
   196         TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javaCmd, "-cp");
       
   197         tr.checkNegative();
       
   198         tr.isNotZeroOutput();
       
   199         System.out.println(tr);
       
   200 
       
   201         tr = TestHelper.doExec(TestHelper.javaCmd, "-classpath");
       
   202         tr.checkNegative();
       
   203         tr.isNotZeroOutput();
       
   204         System.out.println(tr);
       
   205 
       
   206         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar");
       
   207         tr.checkNegative();
       
   208         tr.isNotZeroOutput();
       
   209         System.out.println(tr);
       
   210 
       
   211         tr = TestHelper.doExec(TestHelper.javacCmd, "-cp");
       
   212         tr.checkNegative();
       
   213         tr.isNotZeroOutput();
       
   214         System.out.println(tr);
       
   215 
       
   216         // Test for 6356475 "REGRESSION:"java -X" from cmdline fails"
       
   217         tr = TestHelper.doExec(TestHelper.javaCmd, "-X");
       
   218         tr.checkPositive();
       
   219         tr.isNotZeroOutput();
       
   220         System.out.println(tr);
       
   221 
       
   222         tr = TestHelper.doExec(TestHelper.javaCmd, "-help");
       
   223         tr.checkPositive();
       
   224         tr.isNotZeroOutput();
       
   225         System.out.println(tr);
       
   226     }
       
   227 
       
   228     /*
       
   229      * A set of tests which tests various dispositions of the main method.
       
   230      */
       
   231     static void runMainMethodTests() throws FileNotFoundException {
       
   232         TestHelper.TestResult tr = null;
       
   233 
       
   234         // a missing class
       
   235         TestHelper.createJar(new File("some.jar"), new File("Foo"), (String[])null);
       
   236         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   237         tr.contains("MIA");
       
   238         System.out.println(tr);
       
   239         // use classpath to check
       
   240         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "MIA");
       
   241         tr.contains("Error: Could not find main class MIA");
       
   242         System.out.println(tr);
       
   243 
       
   244         // incorrect method access
       
   245         TestHelper.createJar(new File("some.jar"), new File("Foo"),
       
   246                 "private static void main(String[] args){}");
       
   247         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   248         tr.contains("Error: Main method not found in class Foo");
       
   249         System.out.println(tr);
       
   250         // use classpath to check
       
   251         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "Foo");
       
   252         tr.contains("Error: Main method not found in class Foo");
       
   253         System.out.println(tr);
       
   254 
       
   255         // incorrect return type
       
   256         TestHelper.createJar(new File("some.jar"), new File("Foo"),
       
   257                 "public static int main(String[] args){return 1;}");
       
   258         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   259         tr.contains("Error: Main method must return a value of type void in class Foo");
       
   260         System.out.println(tr);
       
   261         // use classpath to check
       
   262         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "Foo");
       
   263         tr.contains("Error: Main method must return a value of type void in class Foo");
       
   264         System.out.println(tr);
       
   265 
       
   266         // incorrect parameter type
       
   267         TestHelper.createJar(new File("some.jar"), new File("Foo"),
       
   268                 "public static void main(Object[] args){}");
       
   269         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   270         tr.contains("Error: Main method not found in class Foo");
       
   271         System.out.println(tr);
       
   272         // use classpath to check
       
   273         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "Foo");
       
   274         tr.contains("Error: Main method not found in class Foo");
       
   275         System.out.println(tr);
       
   276 
       
   277         // incorrect method type - non-static
       
   278          TestHelper.createJar(new File("some.jar"), new File("Foo"),
       
   279                 "public void main(Object[] args){}");
       
   280         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   281         tr.contains("Error: Main method not found in class Foo");
       
   282         System.out.println(tr);
       
   283         // use classpath to check
       
   284         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "Foo");
       
   285         tr.contains("Error: Main method not found in class Foo");
       
   286         System.out.println(tr);
       
   287 
       
   288         // amongst a potpourri of kindred main methods, is the right one chosen ?
       
   289         TestHelper.createJar(new File("some.jar"), new File("Foo"),
       
   290         "void main(Object[] args){}",
       
   291         "int  main(Float[] args){return 1;}",
       
   292         "private void main() {}",
       
   293         "private static void main(int x) {}",
       
   294         "public int main(int argc, String[] argv) {return 1;}",
       
   295         "public static void main(String[] args) {System.out.println(\"THE_CHOSEN_ONE\");}");
       
   296         tr = TestHelper.doExec(TestHelper.javaCmd, "-jar", "some.jar");
       
   297         tr.contains("THE_CHOSEN_ONE");
       
   298         System.out.println(tr);
       
   299         // use classpath to check
       
   300         tr = TestHelper.doExec(TestHelper.javaCmd, "-cp", "some.jar", "Foo");
       
   301         tr.contains("THE_CHOSEN_ONE");
       
   302         System.out.println(tr);
   147     }
   303     }
   148 
   304 
   149     /**
   305     /**
   150      * @param args the command line arguments
   306      * @param args the command line arguments
   151      */
   307      * @throws java.io.FileNotFoundException
   152     public static void main(String[] args) {
   308      */
   153         if (args.length < 1 && args[0] == null) {
   309     public static void main(String[] args) throws FileNotFoundException {
   154             doUsage("Invalid number of arguments");
   310         if (TestHelper.debug) System.out.println("Starting Arrrghs tests");
   155         }
   311         quoteParsingTests();
   156 
   312         runBasicErrorMessageTests();
   157         javaCmd = args[0];
   313         runMainMethodTests();
   158 
   314         if (TestHelper.testExitValue > 0) {
   159         if (!new File(javaCmd).canExecute()) {
   315             System.out.println("Total of " + TestHelper.testExitValue + " failed");
   160             if (isWindows && new File(javaCmd + ".exe").canExecute()) {
   316             System.exit(1);
   161                 javaCmd = javaCmd + ".exe";
   317         } else {
   162             } else {
   318             System.out.println("All tests pass");
   163                 doUsage("The java executable must exist");
   319         }
   164             }
   320     }
   165         }
       
   166 
       
   167         if (_debug) System.out.println("Starting Arrrghs tests");
       
   168         // Basic test
       
   169         if (!doExec("-a -b -c -d")) exitValue++;
       
   170 
       
   171         // Basic test with many spaces
       
   172         if (!doExec("-a    -b      -c       -d")) exitValue++;
       
   173 
       
   174         // Quoted whitespace does matter ?
       
   175         if (!doExec("-a \"\"-b      -c\"\" -d")) exitValue++;
       
   176 
       
   177         // Escaped quotes outside of quotes as literals
       
   178         if (!doExec("-a \\\"-b -c\\\" -d")) exitValue++;
       
   179 
       
   180         // Check for escaped quotes inside of quotes as literal
       
   181         if (!doExec("-a \"-b \\\"stuff\\\"\" -c -d")) exitValue++;
       
   182 
       
   183         // A quote preceeded by an odd number of slashes is a literal quote
       
   184         if (!doExec("-a -b\\\\\\\" -c -d")) exitValue++;
       
   185 
       
   186         // A quote preceeded by an even number of slashes is a literal quote
       
   187         // see 6214916.
       
   188         if (!doExec("-a -b\\\\\\\\\" -c -d")) exitValue++;
       
   189 
       
   190         // Make sure that whitespace doesn't interfere with the removal of the
       
   191         // appropriate tokens. (space-tab-space preceeds -jre-restict-search).
       
   192         if (!doExec("-a -b  \t -jre-restrict-search -c -d","-a -b -c -d")) exitValue++;
       
   193 
       
   194         // Make sure that the mJRE tokens being stripped, aren't stripped if
       
   195         // they happen to appear as arguments to the main class.
       
   196         if (!doExec("foo -version:1.1+")) exitValue++;
       
   197 
       
   198         System.out.println("Completed Arrrghs arguments quoting/matching tests with " + exitValue + " errors");
       
   199         System.exit(exitValue);
       
   200     }
       
   201 
       
   202 }
   321 }