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
28import jdk.testlibrary.OutputAnalyzer;
29import jdk.testlibrary.ProcessTools;
30
31import java.io.*;
32import java.util.ArrayList;
33import sun.tools.jar.Main;
34
35public 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}
203