1 /* |
|
2 * Copyright (c) 2016, 2018, 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 * @test |
|
26 * @requires vm.cds & !vm.graal.enabled |
|
27 * @summary Testing -Xbootclasspath/a support for CDS |
|
28 * @requires vm.cds |
|
29 * @library /test/lib |
|
30 * @modules java.compiler |
|
31 * java.base/jdk.internal.misc |
|
32 * java.management |
|
33 * jdk.internal.jvmstat/sun.jvmstat.monitor |
|
34 * @compile javax/sound/sampled/MyClass.jasm |
|
35 * @compile javax/annotation/processing/FilerException.jasm |
|
36 * @compile nonjdk/myPackage/MyClass.java |
|
37 * @build LoadClass |
|
38 * @run main/othervm BootAppendTests |
|
39 */ |
|
40 |
|
41 import java.io.File; |
|
42 import java.io.FileOutputStream; |
|
43 import java.io.IOException; |
|
44 import java.io.PrintStream; |
|
45 |
|
46 import java.nio.file.Path; |
|
47 import java.nio.file.Paths; |
|
48 |
|
49 import jdk.test.lib.cds.CDSOptions; |
|
50 import jdk.test.lib.cds.CDSTestUtils; |
|
51 import jdk.test.lib.process.ProcessTools; |
|
52 import jdk.test.lib.process.OutputAnalyzer; |
|
53 |
|
54 public class BootAppendTests { |
|
55 private static final String APP_CLASS = "LoadClass"; |
|
56 private static final String BOOT_APPEND_MODULE_CLASS = "javax/sound/sampled/MyClass"; |
|
57 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = |
|
58 "javax/annotation/processing/FilerException"; |
|
59 private static final String BOOT_APPEND_CLASS = "nonjdk/myPackage/MyClass"; |
|
60 private static final String BOOT_APPEND_MODULE_CLASS_NAME = |
|
61 BOOT_APPEND_MODULE_CLASS.replace('/', '.'); |
|
62 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME = |
|
63 BOOT_APPEND_DUPLICATE_MODULE_CLASS.replace('/', '.'); |
|
64 private static final String BOOT_APPEND_CLASS_NAME = |
|
65 BOOT_APPEND_CLASS.replace('/', '.'); |
|
66 private static final String[] ARCHIVE_CLASSES = |
|
67 {BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS}; |
|
68 |
|
69 private static final String modes[] = {"on", "off"}; |
|
70 |
|
71 private static String appJar; |
|
72 private static String bootAppendJar; |
|
73 |
|
74 public static void main(String... args) throws Exception { |
|
75 dumpArchive(); |
|
76 |
|
77 logTestCase("1"); |
|
78 testBootAppendModuleClass(); |
|
79 |
|
80 logTestCase("2"); |
|
81 testBootAppendDuplicateModuleClass(); |
|
82 |
|
83 logTestCase("3"); |
|
84 testBootAppendExcludedModuleClass(); |
|
85 |
|
86 logTestCase("4"); |
|
87 testBootAppendDuplicateExcludedModuleClass(); |
|
88 |
|
89 logTestCase("5"); |
|
90 testBootAppendClass(); |
|
91 |
|
92 logTestCase("6"); |
|
93 testBootAppendExtraDir(); |
|
94 } |
|
95 |
|
96 private static void logTestCase(String msg) { |
|
97 System.out.println(); |
|
98 System.out.printf("TESTCASE: %s", msg); |
|
99 System.out.println(); |
|
100 } |
|
101 |
|
102 static void dumpArchive() throws Exception { |
|
103 // create the classlist |
|
104 File classlist = CDSTestUtils.makeClassList(ARCHIVE_CLASSES); |
|
105 |
|
106 // build jar files |
|
107 appJar = ClassFileInstaller.writeJar("app.jar", APP_CLASS); |
|
108 bootAppendJar = ClassFileInstaller.writeJar("bootAppend.jar", |
|
109 BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS); |
|
110 |
|
111 |
|
112 OutputAnalyzer out = CDSTestUtils.createArchiveAndCheck( |
|
113 "-Xbootclasspath/a:" + bootAppendJar, |
|
114 "-cp", appJar, |
|
115 "-XX:SharedClassListFile=" + classlist.getPath()); |
|
116 // Make sure all the classes were successfully archived. |
|
117 for (String archiveClass : ARCHIVE_CLASSES) { |
|
118 String msg = "Preload Warning: Cannot find " + archiveClass; |
|
119 if (archiveClass.equals(BOOT_APPEND_MODULE_CLASS)) { |
|
120 // We shouldn't archive a class in the appended boot class path that |
|
121 // are the java.desktop module. Such a class cannot be loaded |
|
122 // at runtime anyway. |
|
123 out.shouldContain(msg); |
|
124 } else { |
|
125 out.shouldNotContain(msg); |
|
126 } |
|
127 } |
|
128 } |
|
129 |
|
130 // Test #1: If a class on -Xbootclasspath/a is from a package defined in |
|
131 // bootmodules, the class is not loaded at runtime. |
|
132 // Verify the behavior is the same when the class is archived |
|
133 // with CDS enabled at runtime. |
|
134 // |
|
135 // The javax.sound.sampled package is defined in the java.desktop module. |
|
136 // The archived javax.sound.sampled.MyClass from the -Xbootclasspath/a |
|
137 // should not be loaded at runtime. |
|
138 public static void testBootAppendModuleClass() throws Exception { |
|
139 for (String mode : modes) { |
|
140 CDSOptions opts = (new CDSOptions()) |
|
141 .setXShareMode(mode).setUseVersion(false) |
|
142 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar, "-showversion") |
|
143 .addSuffix(APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); |
|
144 |
|
145 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); |
|
146 CDSTestUtils.checkExec(out, opts, "java.lang.ClassNotFoundException: javax.sound.sampled.MyClass"); |
|
147 } |
|
148 } |
|
149 |
|
150 // Test #2: If a class on -Xbootclasspath/a has the same fully qualified |
|
151 // name as a class defined in boot modules, the class is not loaded |
|
152 // from -Xbootclasspath/a. Verify the behavior is the same at runtime |
|
153 // when CDS is enabled. |
|
154 // |
|
155 // The javax/annotation/processing/FilerException is a platform module |
|
156 // class. The class on the -Xbootclasspath/a path that has the same |
|
157 // fully-qualified name should not be loaded at runtime when CDS is enabled. |
|
158 // The one from the platform modules should be loaded instead. |
|
159 public static void testBootAppendDuplicateModuleClass() throws Exception { |
|
160 for (String mode : modes) { |
|
161 CDSOptions opts = (new CDSOptions()) |
|
162 .setXShareMode(mode).setUseVersion(false) |
|
163 .addPrefix("-showversion", |
|
164 "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar) |
|
165 .addSuffix("-Xlog:class+load=info", |
|
166 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); |
|
167 |
|
168 String MATCH_PATTERN = ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; |
|
169 CDSTestUtils.run(opts) |
|
170 .assertNormalExit(out -> { |
|
171 out.shouldNotMatch(MATCH_PATTERN); |
|
172 }); |
|
173 } |
|
174 } |
|
175 |
|
176 // Test #3: If a class on -Xbootclasspath/a is from a package defined in boot modules, |
|
177 // the class can be loaded from -Xbootclasspath/a when the module is excluded |
|
178 // using --limit-modules. Verify the behavior is the same at runtime when CDS |
|
179 // is enabled. |
|
180 // |
|
181 // The java.desktop module is excluded using --limit-modules at runtime |
|
182 // CDS will be disabled with the --limit-modules option during runtime. |
|
183 // javax.sound.sampled.MyClass will be loaded from the jar at runtime. |
|
184 public static void testBootAppendExcludedModuleClass() throws Exception { |
|
185 for (String mode : modes) { |
|
186 CDSOptions opts = (new CDSOptions()) |
|
187 .setXShareMode(mode).setUseVersion(false) |
|
188 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", |
|
189 "--limit-modules=java.base", "-cp", appJar) |
|
190 .addSuffix("-Xlog:class+load=info", |
|
191 APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); |
|
192 CDSTestUtils.Result res = CDSTestUtils.run(opts); |
|
193 String MATCH_PATTERN = |
|
194 ".class.load. javax.sound.sampled.MyClass source:.*bootAppend.jar*"; |
|
195 if (mode.equals("on")) { |
|
196 res.assertSilentlyDisabledCDS(out -> { |
|
197 out.shouldHaveExitValue(0) |
|
198 .shouldMatch(MATCH_PATTERN); |
|
199 }); |
|
200 } else { |
|
201 res.assertNormalExit(out -> { |
|
202 out.shouldMatch(MATCH_PATTERN); |
|
203 }); |
|
204 } |
|
205 } |
|
206 } |
|
207 |
|
208 // Test #4: If a class on -Xbootclasspath/a has the same fully qualified |
|
209 // name as a class defined in boot modules, the class is loaded |
|
210 // from -Xbootclasspath/a when the boot module is excluded using |
|
211 // --limit-modules. Verify the behavior is the same at runtime |
|
212 // when CDS is enabled. |
|
213 // |
|
214 // The javax.annotation.processing.FilerException is a platform module class. |
|
215 // The class on -Xbootclasspath/a that has the same fully-qualified name |
|
216 // as javax.annotation.processing.FilerException can be loaded at runtime when |
|
217 // java.compiler is excluded. |
|
218 // CDS is disabled during runtime if the --limit-modules option is |
|
219 // specified. |
|
220 public static void testBootAppendDuplicateExcludedModuleClass() throws Exception { |
|
221 for (String mode : modes) { |
|
222 CDSOptions opts = (new CDSOptions()) |
|
223 .setXShareMode(mode).setUseVersion(false) |
|
224 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", |
|
225 "--limit-modules=java.base", "-cp", appJar) |
|
226 .addSuffix("-Xlog:class+load=info", |
|
227 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); |
|
228 |
|
229 CDSTestUtils.Result res = CDSTestUtils.run(opts); |
|
230 String MATCH_PATTERN = |
|
231 ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; |
|
232 if (mode.equals("on")) { |
|
233 res.assertSilentlyDisabledCDS(out -> { |
|
234 out.shouldHaveExitValue(0) |
|
235 .shouldMatch(MATCH_PATTERN); |
|
236 }); |
|
237 } else { |
|
238 res.assertNormalExit(out -> { |
|
239 out.shouldMatch(MATCH_PATTERN); |
|
240 }); |
|
241 } |
|
242 } |
|
243 } |
|
244 |
|
245 // Test #5: If a class on -Xbootclasspath/a is not from named modules, |
|
246 // the class can be loaded at runtime. Verify the behavior is |
|
247 // the same at runtime when CDS is enabled. |
|
248 // |
|
249 // The nonjdk.myPackage is not defined in named modules. The |
|
250 // nonjdk.myPackage.MyClass will be loaded from the jar in |
|
251 // -Xbootclasspath/a since CDS will be disabled with the |
|
252 // --limit-modules option. |
|
253 public static void testBootAppendClass() throws Exception { |
|
254 for (String mode : modes) { |
|
255 CDSOptions opts = (new CDSOptions()) |
|
256 .setXShareMode(mode).setUseVersion(false) |
|
257 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", |
|
258 "--limit-modules=java.base", "-cp", appJar) |
|
259 .addSuffix("-Xlog:class+load=info", |
|
260 APP_CLASS, BOOT_APPEND_CLASS_NAME); |
|
261 |
|
262 CDSTestUtils.Result res = CDSTestUtils.run(opts); |
|
263 String MATCH_PATTERN = |
|
264 ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; |
|
265 if (mode.equals("on")) { |
|
266 res.assertSilentlyDisabledCDS(out -> { |
|
267 out.shouldHaveExitValue(0) |
|
268 .shouldMatch(MATCH_PATTERN); |
|
269 }); |
|
270 } else { |
|
271 res.assertNormalExit(out -> { |
|
272 out.shouldMatch(MATCH_PATTERN); |
|
273 }); |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 // Test #6: This is similar to Test #5. During runtime, an extra dir |
|
279 // is appended to the bootclasspath. It should not invalidate |
|
280 // the shared archive. However, CDS will be disabled with the |
|
281 // --limit-modules in the command line. |
|
282 public static void testBootAppendExtraDir() throws Exception { |
|
283 for (String mode : modes) { |
|
284 CDSOptions opts = (new CDSOptions()) |
|
285 .setXShareMode(mode).setUseVersion(false) |
|
286 .addPrefix("-Xbootclasspath/a:" + bootAppendJar + File.pathSeparator + appJar, |
|
287 "-showversion", "--limit-modules=java.base", "-cp", appJar) |
|
288 .addSuffix("-Xlog:class+load=info", |
|
289 APP_CLASS, BOOT_APPEND_CLASS_NAME); |
|
290 |
|
291 CDSTestUtils.Result res = CDSTestUtils.run(opts); |
|
292 String MATCH_PATTERN = |
|
293 ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; |
|
294 if (mode.equals("on")) { |
|
295 res.assertSilentlyDisabledCDS(out -> { |
|
296 out.shouldHaveExitValue(0) |
|
297 .shouldMatch(MATCH_PATTERN); |
|
298 }); |
|
299 } else { |
|
300 res.assertNormalExit(out -> { |
|
301 out.shouldMatch(MATCH_PATTERN); |
|
302 }); |
|
303 } |
|
304 } |
|
305 } |
|
306 } |
|