1 /*
   2  * Copyright (c) 2015, 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 /**
  26  * @test
  27  * @requires vm.cds
  28  * @modules java.base/jdk.internal.misc
  29  * @library ../..
  30  * @library /test/lib
  31  * @run main OverrideTests
  32  * @summary AppCDS tests for overriding archived classes with -p and --upgrade-module-path
  33  */
  34 
  35 /*
  36  * This test consists of 4 tests:
  37  *   1. Archive PLATFORM class and override with --upgrade-module-path.
  38  *   2. Archive PLATFORM class and override with -p.
  39  *   3. Archive APP class and override with --upgrade-module-path.
  40  *   4. Archive App class and override with -p.
  41  * For all 4 tests, the class is instantiatied and toString() is called
  42  * to check whether the archived version or the override version was instantiatied.
  43  * For tests 1 and 3, the overridden version should be instantiatied.
  44  * For tests 2 and 4, the archived version should be instantiated.
  45  *
  46  * This test uses the same test helper class in all 4 cases. It is located in
  47  * src/test/jdk/test/Main.java. It will be invoked once for each test cases,
  48  * with parameters to the test determining how it is run and what the
  49  * expected result is. See Main.java for a description of these 3 arguments.
  50  */
  51 
  52 import java.io.File;
  53 import java.nio.file.Files;
  54 import java.nio.file.Path;
  55 import java.nio.file.Paths;
  56 
  57 import jdk.test.lib.Asserts;
  58 import jdk.test.lib.cds.CDSOptions;
  59 import jdk.test.lib.cds.CDSTestUtils;
  60 import jdk.test.lib.process.OutputAnalyzer;
  61 import jdk.test.lib.process.ProcessTools;
  62 
  63 
  64 public class OverrideTests {
  65     private static final String TEST_SRC = System.getProperty("test.src");
  66     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  67     private static final Path MODS_DIR = Paths.get("mods");
  68 
  69     // the module that is upgraded
  70     private static final String[] UPGRADED_MODULES = {"jdk.compiler", "java.net.http"};
  71     private static final Path[] UPGRADEDMODS_DIR = {Paths.get("upgradedmod1"), Paths.get("upgradedmod2")};
  72 
  73     // the test module
  74     private static final String TEST_MODULE = "test";
  75     private static final String MAIN_CLASS = "jdk.test.Main";
  76 
  77     // test classes to archive. These are both in UPGRADED_MODULES
  78     private static final String APP_ARCHIVE_CLASS = "com/sun/tools/javac/Main";
  79     private static final String PLATFORM_ARCHIVE_CLASS = "java/net/http/HttpTimeoutException";
  80     private static final String[] ARCHIVE_CLASSES = {APP_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS};
  81     private static String testArchiveName;
  82 
  83 
  84     public static void main(String[] args) throws Exception {
  85         OverrideTests tests = new OverrideTests();
  86         tests.compileModulesAndDumpArchive();
  87         tests.testAppClassOverriding();
  88         tests.testPlatformClassOverriding();
  89     }
  90 
  91     void compileModulesAndDumpArchive() throws Exception {
  92         boolean compiled;
  93         // javac -d upgradedmods/$upgradedMod src/$upgradedMod/**
  94         int i = 0;
  95         for (String upgradedMod : UPGRADED_MODULES) {
  96             compiled = CompilerUtils.compile(
  97                 SRC_DIR.resolve(UPGRADED_MODULES[i]),
  98                 UPGRADEDMODS_DIR[i].resolve(UPGRADED_MODULES[i])
  99             );
 100             Asserts.assertTrue(compiled, UPGRADED_MODULES[i] + " did not compile");
 101             i++;
 102         }
 103 
 104         // javac -d mods/test --upgrade-module-path upgradedmods ...
 105         compiled = CompilerUtils.compile(
 106             SRC_DIR.resolve(TEST_MODULE),
 107             MODS_DIR.resolve(TEST_MODULE),
 108             "--upgrade-module-path", UPGRADEDMODS_DIR[0].toString() +
 109              System.getProperty("path.separator") + UPGRADEDMODS_DIR[1].toString()
 110         );
 111         Asserts.assertTrue(compiled, TEST_MODULE + " did not compile");
 112 
 113         // dump the archive with jdk.compiler and java.net.http classes in the class list
 114         OutputAnalyzer output  = TestCommon.dump(null /* appJar*/, TestCommon.list(ARCHIVE_CLASSES));
 115         TestCommon.checkDump(output);
 116         // Make sure all the classes where successfully archived.
 117         for (String archiveClass : ARCHIVE_CLASSES) {
 118             output.shouldNotContain("Preload Warning: Cannot find " + archiveClass);
 119         }
 120 
 121         testArchiveName = TestCommon.getCurrentArchiveName();
 122     }
 123 
 124     /**
 125      * APP Class Overriding Tests
 126      *
 127      * Archive APP class com.sun.tools.javac.Main from module jdk.compiler.
 128      *  -At run time, upgrade module jdk.compiler using --upgrade-module-path.
 129      *   Class.forname(Main) MUST NOT load the archived Main.
 130      *  -At run time, module jdk.compiler also exists in --module-path.
 131      *   Class.forname(Main) MUST load the archived Main.
 132      */
 133     public void testAppClassOverriding() throws Exception {
 134         testClassOverriding(APP_ARCHIVE_CLASS, "app");
 135     }
 136 
 137     /**
 138      * PLATFORM Class Overriding Tests
 139      *
 140      * Archive PLATFORM class java.net.http.HttpTimeoutException from module java.net.http.
 141      *  -At run time, upgrade module java.net.http using --upgrade-module-path.
 142      *   Class.forname(HttpTimeoutException) MUST NOT load the archived HttpTimeoutException.
 143      *  -At run time, module java.net.http also exists in --module-path.
 144      *   Class.forname(HttpTimeoutException) MUST load the archived HttpTimeoutException.
 145      */
 146     public void testPlatformClassOverriding() throws Exception {
 147         testClassOverriding(PLATFORM_ARCHIVE_CLASS, "platform");
 148     }
 149 
 150     /**
 151      * Run the test twice. Once with upgrade module on --upgrade-module-path and once with it on -p.
 152      * Only modules defined to the PlatformClassLoader are upgradeable.
 153      * Modules defined to the AppClassLoader are not upgradeble; we expect the
 154      * FindException to be thrown.
 155      */
 156     void testClassOverriding(String archiveClass, String loaderName) throws Exception {
 157         String mid = TEST_MODULE + "/" + MAIN_CLASS;
 158         OutputAnalyzer output;
 159         boolean isAppLoader = loaderName.equals("app");
 160         int upgradeModIdx = isAppLoader ? 0 : 1;
 161         String expectedException = "java.lang.module.FindException: Unable to compute the hash";
 162         String prefix[] = new String[4];
 163         prefix[0] = "-cp";
 164         prefix[1] = "\"\"";
 165         prefix[2] = "--add-modules";
 166         prefix[3] = "java.net.http";
 167 
 168         // Run the test with --upgrade-module-path set to alternate location of archiveClass
 169         // The alternate version of archiveClass SHOULD be found.
 170         TestCommon.runWithModules(prefix,
 171                                   UPGRADEDMODS_DIR[upgradeModIdx].toString(),
 172                                   MODS_DIR.toString(),
 173                                   mid,
 174                                   archiveClass, loaderName, "true") // last 3 args passed to test
 175             .ifNoMappingFailure(out -> out.shouldContain(expectedException));
 176 
 177         // Now run this same test again, but this time without AppCDS. Behavior should be the same.
 178         CDSOptions opts = (new CDSOptions())
 179             .addPrefix(prefix)
 180             .setArchiveName(testArchiveName).setUseVersion(false)
 181             .addSuffix("--upgrade-module-path", UPGRADEDMODS_DIR[upgradeModIdx].toString(),
 182                        "-p", MODS_DIR.toString(), "-m", mid)
 183             .addSuffix(archiveClass, loaderName, "true");
 184 
 185         output = CDSTestUtils.runWithArchive(opts);
 186 
 187         try {
 188             output.shouldContain(expectedException);
 189         } catch (Exception e) {
 190             TestCommon.checkCommonExecExceptions(output, e);
 191         }
 192 
 193         // Run the test with -p set to alternate location of archiveClass.
 194         // The alternate version of archiveClass SHOULD NOT be found.
 195         TestCommon.runWithModules(
 196             prefix,
 197             null,
 198             UPGRADEDMODS_DIR[upgradeModIdx].toString() + java.io.File.pathSeparator + MODS_DIR.toString(),
 199             mid,
 200             archiveClass, loaderName, "false") // last 3 args passed to test
 201             .assertNormalExit();
 202 
 203         // Now  run this same test again, but this time without AppCDS. Behavior should be the same.
 204         opts = (new CDSOptions())
 205             .addPrefix(prefix)
 206             .setArchiveName(testArchiveName).setUseVersion(false)
 207             .addSuffix("-p", MODS_DIR.toString(), "-m", mid)
 208             .addSuffix(archiveClass, loaderName, "false"); // params to the test class
 209 
 210         OutputAnalyzer out = CDSTestUtils.runWithArchive(opts);
 211         if (!CDSTestUtils.isUnableToMap(out))
 212             out.shouldHaveExitValue(0);
 213     }
 214 }