1 /* 2 * Copyright (c) 2016, 2021, 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 // Structure of the test: 26 // TransformRelatedClassesAppCDS -- common main test driver 27 // Invoked from test driver classes: 28 // TransformInterfaceAndImplementor, TransformSuperAndSubClasses.java 29 // prepares test artifacts, launches tests, checks results 30 // SuperClazz, SubClass -- classes under test 31 // Interface, Implementor -- classes under test 32 // TransformerAgent -- an agent that is used when JVM-under-test is executed 33 // to transform specific strings inside specified classes 34 // TransformerAgent.mf - accompanies transformer agent 35 // CustomLoaderApp -- a test "application" that is used to load 36 // classes-under-test (Parent, Child) via custom class loader, using 37 // AppCDS-v2 mechanism (unregistered custom loaders, aka FP) 38 // This "app" is launched in a child process by this driver with sharing on. 39 40 import java.io.File; 41 import java.util.ArrayList; 42 import jdk.test.lib.Platform; 43 import jdk.test.lib.process.OutputAnalyzer; 44 import jdk.test.lib.helpers.ClassFileInstaller; 45 46 // This class is intended to test 2 parent-child relationships: 47 // 1. Base Class (parent) and Derived Class (child) 48 // 2. Interface (parent) and Implementor (child) 49 // Parameters to main(): parent, child 50 51 public class TransformRelatedClassesAppCDS extends TransformRelatedClasses { 52 private static void log(String msg, Object... args) { 53 String msg0 = String.format(msg, args); 54 System.out.println("TransformRelatedClassesAppCDS: " + msg0); 55 } 56 57 // Initial Test Matrix: 58 // (ParentTransformed = true/false, ChildTransformed = true/false) x 59 // (BootCDS - see open tests, AppCDS-v1, AppCDS-v2-unregistered) 60 // Total cases: 2 x 4 = 8 61 public static void main(String args[]) throws Exception { 62 TransformRelatedClassesAppCDS test = 63 new TransformRelatedClassesAppCDS(args[0], args[1]); 64 65 test.prepareAgent(agentClasses); 66 67 // Test Table 68 // testCaseId | transformParent | tranformChild | isParentExpectedShared | isChildExpectedShared 69 ArrayList<TestEntry> testTable = new ArrayList<>(); 70 71 // base case - no tranformation - all expected to be shared 72 testTable.add(new TestEntry(0, false, false, true, true)); 73 74 // transform parent only - both parent and child should not be shared 75 testTable.add(new TestEntry(1, true, false, false, false)); 76 77 // transform parent and child - both parent and child should not be shared 78 testTable.add(new TestEntry(2, true, true, false, false)); 79 80 // transform child only - parent should still be shared, but not child 81 testTable.add(new TestEntry(3, false, true, true, false)); 82 83 // run the tests 84 test.runWithAppLoader(testTable); 85 test.runWithCustomLoader(testTable); 86 } 87 88 89 public TransformRelatedClassesAppCDS(String parent, String child) { 90 super(parent, child); 91 92 // a trick to get it compiled by jtreg 93 CustomLoaderApp.ping(); 94 } 95 96 97 private void prepareAgent(String[] agentClasses) throws Exception { 98 String manifest = "../../../../../testlibrary/jvmti/TransformerAgent.mf"; 99 agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar", 100 ClassFileInstaller.Manifest.fromSourceFile(manifest), 101 agentClasses); 102 } 103 104 105 private void runWithAppLoader(ArrayList<TestEntry> testTable) throws Exception { 106 String appJar = writeJar("app", testClasses); 107 108 // create an archive 109 OutputAnalyzer out = TestCommon.dump(appJar, testClasses); 110 TestCommon.checkDump(out); 111 112 // execute with archive 113 for (TestEntry entry : testTable) { 114 log("runTestWithAppLoader(): testCaseId = %d", entry.testCaseId); 115 String params = TransformTestCommon.getAgentParams(entry, parent, child); 116 String agentParam = String.format("-javaagent:%s=%s", agentJar, params); 117 TestCommon.run("-Xlog:class+load=info", "-cp", appJar, 118 agentParam, child) 119 .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child)); 120 } 121 } 122 123 124 private String[] getCustomClassList(String loaderType, String customJar) { 125 String type = child + "-" + loaderType; 126 127 switch (type) { 128 129 case "SubClass-unregistered": 130 return new String[] { 131 "CustomLoaderApp", 132 "java/lang/Object id: 0", 133 parent + " id: 1 super: 0 source: " + customJar, 134 child + " id: 2 super: 1 source: " + customJar, 135 }; 136 137 case "Implementor-unregistered": 138 return new String[] { 139 "CustomLoaderApp", 140 "java/lang/Object id: 0", 141 parent + " id: 1 super: 0 source: " + customJar, 142 child + " id: 2 super: 0 interfaces: 1 source: " + customJar, 143 }; 144 145 default: 146 throw new IllegalArgumentException("getCustomClassList - wrong type: " + type); 147 } 148 } 149 150 151 private void runWithCustomLoader(ArrayList<TestEntry> testTable) throws Exception { 152 if (!Platform.areCustomLoadersSupportedForCDS()) { 153 log("custom loader not supported for this platform" + 154 " - skipping test case for custom loader"); 155 return; 156 } 157 158 if (TestCommon.isDynamicArchive()) { 159 log("custom loader class list not applicable to dynamic archive" + 160 " - skipping test case for custom loader"); 161 return; 162 } 163 164 String appClasses[] = { 165 "CustomLoaderApp", 166 }; 167 168 String customClasses[] = { parent, child }; 169 170 // create jar files: appJar, customJar (for custom loaders to load classes from) 171 String appJar = writeJar("custldr-app", appClasses); 172 String customJar = writeJar("custldr-custom", customClasses); 173 174 for (TestEntry entry : testTable) { 175 log("runTestWithCustomLoader(): testCaseId = %d", entry.testCaseId); 176 // unregistered (aka FP) case 177 String[] classList = getCustomClassList("unregistered",customJar); 178 execAndCheckWithCustomLoader(entry, "unregistered", classList, 179 appJar, agentJar, customJar); 180 } 181 } 182 183 184 private void 185 execAndCheckWithCustomLoader(TestEntry entry, String loaderType, 186 String[] classList, String appJar, 187 String agentJar, String customJar) 188 throws Exception { 189 190 OutputAnalyzer out = TestCommon.dump(appJar, classList); 191 TestCommon.checkDump(out); 192 193 String agentParam = "-javaagent:" + agentJar + "=" + 194 TransformTestCommon.getAgentParams(entry, parent, child); 195 196 TestCommon.run("-Xlog:class+load=info", 197 "-cp", appJar, 198 agentParam, 199 "CustomLoaderApp", 200 customJar, loaderType, child) 201 .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child)); 202 } 203 204 205 private String writeJar(String type, String[] classes) 206 throws Exception { 207 String jarName = String.format("%s-%s.jar", child, type); 208 return ClassFileInstaller.writeJar(jarName, classes); 209 } 210 }