1 /*
   2  * Copyright (c) 2013, 2015, 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 /*
  25  * Helper superclass for launching JDI tests out of the CDS archive.
  26 */
  27 
  28 import jdk.test.lib.process.OutputAnalyzer;
  29 import jdk.test.lib.process.ProcessTools;
  30 
  31 import java.io.*;
  32 import java.util.ArrayList;
  33 import sun.tools.jar.Main;
  34 
  35 public class CDSJDITest {
  36     private static final String classesDir = System.getProperty("test.classes");
  37 
  38     public static void runTest(String testname, String[] jarClasses) throws Exception {
  39         File jarClasslistFile = makeClassList(jarClasses);
  40         String appJar = buildJar(testname, jarClasses);
  41 
  42         // These are the arguments passed to createJavaProcessBuilder() to launch
  43         // the JDI test.
  44         String[] testArgs = {
  45         // JVM Args:
  46             // These first three properties are setup by jtreg, and must be passed
  47             // to the JDI test subprocess because it needs them in order to
  48             // pass them to the subprocess it will create for the debuggee. This
  49             // is how the JPRT -javaopts are passed to the debggee. See
  50             // VMConnection.getDebuggeeVMOptions().
  51             getPropOpt("test.classes"),
  52             getPropOpt("test.java.opts"),
  53             getPropOpt("test.vm.opts"),
  54             // Pass -showversion to the JDI test just so we get a bit of trace output.
  55             "-showversion",
  56         // Main class:
  57             testname,
  58         // Args to the Main Class:
  59             // These argument all follow the above <testname> argument, and are
  60             // in fact passed to <testname>.main() as java arguments. <testname> will
  61             // pass them as JVM arguments to the debuggee process it creates.
  62             "-Xbootclasspath/a:" + appJar,
  63             "-XX:+UnlockDiagnosticVMOptions",
  64             "-XX:+TraceClassPaths",
  65             "-XX:SharedArchiveFile=./SharedArchiveFile.jsa",
  66             "-Xshare:on",
  67             "-showversion"
  68         };
  69 
  70         // Dump the archive
  71         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
  72             "-Xbootclasspath/a:" + appJar,
  73             "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedArchiveFile.jsa",
  74             "-XX:ExtraSharedClassListFile=" + jarClasslistFile.getPath(),
  75             "-Xshare:dump");
  76         OutputAnalyzer outputDump = executeAndLog(pb, "exec");
  77         for (String jarClass : jarClasses) {
  78             outputDump.shouldNotContain("Cannot find " + jarClass);
  79         }
  80         outputDump.shouldContain("Loading classes to share");
  81         outputDump.shouldHaveExitValue(0);
  82 
  83         // Run the test specified JDI test
  84         pb = ProcessTools.createJavaProcessBuilder(true, testArgs);
  85         OutputAnalyzer outputRun = executeAndLog(pb, "exec");
  86         try {
  87             outputRun.shouldContain("sharing");
  88             outputRun.shouldHaveExitValue(0);
  89         } catch (RuntimeException e) {
  90             outputRun.shouldContain("Unable to use shared archive");
  91             outputRun.shouldHaveExitValue(1);
  92         }
  93     }
  94 
  95     public static String getPropOpt(String prop) {
  96         String propVal = System.getProperty(prop);
  97         if (propVal == null) propVal = "";
  98         System.out.println(prop + ": '" + propVal  + "'");
  99         return "-D" + prop + "=" + propVal;
 100     }
 101 
 102     public static File makeClassList(String appClasses[]) throws Exception {
 103         File classList = getOutputFile("test.classlist");
 104         FileOutputStream fos = new FileOutputStream(classList);
 105         PrintStream ps = new PrintStream(fos);
 106 
 107         addToClassList(ps, appClasses);
 108 
 109         ps.close();
 110         fos.close();
 111 
 112         return classList;
 113     }
 114 
 115     public static OutputAnalyzer executeAndLog(ProcessBuilder pb, String logName) throws Exception {
 116         long started = System.currentTimeMillis();
 117         OutputAnalyzer output = ProcessTools.executeProcess(pb);
 118         writeFile(getOutputFile(logName + ".stdout"), output.getStdout());
 119         writeFile(getOutputFile(logName + ".stderr"), output.getStderr());
 120         System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]");
 121         System.out.println("[STDOUT]\n" + output.getStdout());
 122         System.out.println("[STDERR]\n" + output.getStderr());
 123         return output;
 124     }
 125 
 126     private static void writeFile(File file, String content) throws Exception {
 127         FileOutputStream fos = new FileOutputStream(file);
 128         PrintStream ps = new PrintStream(fos);
 129         ps.print(content);
 130         ps.close();
 131         fos.close();
 132     }
 133 
 134     public static File getOutputFile(String name) {
 135         File dir = new File(System.getProperty("test.classes", "."));
 136         return new File(dir, getTestNamePrefix() + name);
 137     }
 138 
 139     private static void addToClassList(PrintStream ps, String classes[]) throws IOException {
 140         if (classes != null) {
 141             for (String s : classes) {
 142                 ps.println(s);
 143             }
 144         }
 145     }
 146 
 147     private static String testNamePrefix;
 148 
 149     private static String getTestNamePrefix() {
 150         if (testNamePrefix == null) {
 151             StackTraceElement[] elms = (new Throwable()).getStackTrace();
 152             if (elms.length > 0) {
 153                 for (StackTraceElement n: elms) {
 154                     if ("main".equals(n.getMethodName())) {
 155                         testNamePrefix = n.getClassName() + "-";
 156                         break;
 157                     }
 158                 }
 159             }
 160 
 161             if (testNamePrefix == null) {
 162                 testNamePrefix = "";
 163             }
 164         }
 165         return testNamePrefix;
 166     }
 167 
 168     private static String buildJar(String jarName, String ...classNames)
 169         throws Exception {
 170 
 171         String jarFullName = classesDir + File.separator + jarName + ".jar";
 172         createSimpleJar(classesDir, jarFullName, classNames);
 173         return jarFullName;
 174     }
 175 
 176     private static void createSimpleJar(String jarClassesDir, String jarName,
 177         String[] classNames) throws Exception {
 178 
 179         ArrayList<String> args = new ArrayList<String>();
 180         args.add("cf");
 181         args.add(jarName);
 182         addJarClassArgs(args, jarClassesDir, classNames);
 183         createJar(args);
 184     }
 185 
 186     private static void addJarClassArgs(ArrayList<String> args, String jarClassesDir,
 187         String[] classNames) {
 188 
 189         for (String name : classNames) {
 190             args.add("-C");
 191             args.add(jarClassesDir);
 192             args.add(name + ".class");
 193         }
 194     }
 195 
 196     private static void createJar(ArrayList<String> args) {
 197         Main jarTool = new Main(System.out, System.err, "jar");
 198         if (!jarTool.run(args.toArray(new String[1]))) {
 199             throw new RuntimeException("jar operation failed");
 200         }
 201     }
 202 }