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 // This is the main test class for testing transformation of related classes
 26 // in combination with CDS, to ensure these features work well together.
 27 // The relationships that can be tested using this test class are:
 28 // superclass/subclass, and interface/implementor relationships.
 29 //
 30 // The test uses combinatorial approach.
 31 // For details on test table and test cases see main() method in this class.
 32 //
 33 // This test consists of multiple classes for better flexibility and reuse,
 34 // and also relies on certain common utility code.
 35 // Here are the details on the structure of the test
 36 //
 37 // Structure of the test:
 38 // TransformRelatedClasses -- common main test driver
 39 //     The TransformRelatedClasses is invoked from test driver classes:
 40 //     TransformInterfaceAndImplementor, TransformSuperAndSubClasses
 41 //     It is responsible for preparing test artifacts (test jar, agent jar
 42 //     and the shared archive), running test cases and checking the results.
 43 // The following test classes below are launched in a sub-process with use
 44 // of shared archive:
 45 //     SuperClazz, SubClass -- super/sub class pair under test
 46 //     Interface, Implementor -- classes under test
 47 // This test will transform these classes, based on the test case data,
 48 // by changing a predefined unique string in each class.
 49 // For more details, see the test classes' code and comments.
 50 //
 51 // Other related classes:
 52 //     TestEntry - a class representing a single test case, as test entry in the table
 53 //     TransformTestCommon - common methods for transformation test cases
 54 //
 55 // Other utility/helper classes and files used in this test:
 56 //     TransformerAgent - an agent that is used when JVM-under-test is executed
 57 //         to transform specific strings inside specified classes
 58 //     TransformerAgent.mf - accompanies transformer agent
 59 
 60 import java.io.File;
 61 import java.util.ArrayList;
 62 import jdk.test.lib.cds.CDSOptions;
 63 import jdk.test.lib.cds.CDSTestUtils;
 64 import jdk.test.lib.process.OutputAnalyzer;
 65 import jdk.test.lib.process.ProcessTools;
 66 import jdk.test.lib.helpers.ClassFileInstaller;
 67 
 68 
 69 public class TransformRelatedClasses {
 70     static final String archiveName = "./TransformRelatedClasses.jsa";
 71     static String agentClasses[] = {
 72         "TransformerAgent",
 73         "TransformerAgent$SimpleTransformer",
 74         "TransformUtil"
 75     };
 76 
 77     String parent;
 78     String child;
 79     String[] testClasses = new String[2];
 80     String[] testNames = new String[2];
 81     String testJar;
 82     String agentJar;
 83 
 84 
 85     private static void log(String msg) {
 86         System.out.println("TransformRelatedClasses: " + msg);
 87     }
 88 
 89 
 90     // This class is intended to test 2 parent-child relationships:
 91     // 1. Base Class (parent) and Derived Class (child)
 92     // 2. Interface (parent) and Implementor (child)
 93     //    Parameters to main(): parent, child
 94     public static void main(String args[]) throws Exception {
 95         TransformRelatedClasses test = new TransformRelatedClasses(args[0], args[1]);
 96         test.prepare();
 97 
 98         // Test Table
 99         // TestEntry:  (testCaseId, transformParent, tranformChild,
100         //             isParentExpectedShared, isChildExpectedShared)
101         ArrayList<TestEntry> testTable = new ArrayList<>();
102 
103         // base case - no tranformation - all expected to be shared
104         testTable.add(new TestEntry(0, false, false, true, true));
105 
106         // transform parent only - both parent and child should not be shared
107         testTable.add(new TestEntry(1, true, false, false, false));
108 
109         // transform parent and child - both parent and child should not be shared
110         testTable.add(new TestEntry(2, true, true, false, false));
111 
112         // transform child only - parent should still be shared, but not child
113         testTable.add(new TestEntry(3, false, true, true, false));
114 
115         // run the tests
116         for (TestEntry entry : testTable) {
117             test.runTest(entry);
118         }
119     }
120 
121 
122     public TransformRelatedClasses(String parent, String child) {
123         log("Constructor: parent = " + parent + ", child = " + child);
124         this.parent = parent;
125         this.child = child;
126         testClasses[0] = parent;
127         testClasses[1] = child;
128         testNames[0] = parent.replace('.', '/');
129         testNames[1] = child.replace('.', '/');
130     }
131 
132 
133     // same test jar and archive can be used for all test cases
134     private void prepare() throws Exception {
135         // create agent jar
136         // Agent is the same for all test cases
137         String pathToManifest = "../../../../testlibrary/jvmti/TransformerAgent.mf";
138         agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar",
139                        ClassFileInstaller.Manifest.fromSourceFile(pathToManifest),
140                                            agentClasses);
141 
142         // create a test jar
143         testJar =
144             ClassFileInstaller.writeJar(parent + "-" + child + ".jar",
145                                            testClasses);
146 
147         // create an archive
148         String classList =
149             CDSTestUtils.makeClassList("transform-" + parent, testNames).getPath();
150 
151         CDSTestUtils.createArchiveAndCheck("-Xbootclasspath/a:" + testJar,
152             "-XX:ExtraSharedClassListFile=" + classList, "-XX:-PreloadSharedClasses");
153     }
154 
155 
156     private void runTest(TestEntry entry) throws Exception {
157         log("runTest(): testCaseId = " + entry.testCaseId);
158 
159         // execute with archive
160         String agentParam = "-javaagent:" + agentJar + "=" +
161             TransformTestCommon.getAgentParams(entry, parent, child);
162 
163         CDSOptions opts = new CDSOptions()
164             .addPrefix("-Xbootclasspath/a:" + testJar, "-Xlog:class+load=info")
165             .setUseVersion(false)
166             .addSuffix( "-showversion",agentParam, child);
167 
168         OutputAnalyzer out = CDSTestUtils.runWithArchive(opts);
169         TransformTestCommon.checkResults(entry, out, parent, child);
170     }
171 }