1 /*
   2  * Copyright (c) 2020, 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  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
  29  * @run driver OptimizeModuleHandlingTest
  30  * @summary test module path changes for optimization of
  31  *          module handling.
  32  *
  33  */
  34 
  35 import java.io.File;
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.nio.file.Paths;
  39 
  40 import jdk.test.lib.process.OutputAnalyzer;
  41 import jdk.test.lib.Platform;
  42 
  43 public class OptimizeModuleHandlingTest {
  44 
  45     private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
  46 
  47     private static final String TEST_SRC = System.getProperty("test.src");
  48 
  49     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  50     private static final Path MODS_DIR = Paths.get("mody");
  51 
  52     // the module name of the test module
  53     private static final String MAIN_MODULE = "com.bars";
  54     private static final String TEST_MODULE = "com.foos";
  55 
  56     // the module main class
  57     private static final String MAIN_CLASS = "com.bars.Main";
  58     private static final String TEST_CLASS = "com.foos.Test";
  59 
  60     private static String PATH_LIBS = "modylibs";
  61     private static Path libsDir = null;
  62     private static Path mainJar = null;
  63     private static Path testJar = null;
  64 
  65     private static String CLASS_FOUND_MESSAGE = "com.foos.Test found";
  66     private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test";
  67     private static String OPTIMIZE_ENABLED = "Using optimized module handling";
  68     private static String OPTIMIZE_DISABLED = "use_optimized_module_handling disabled";
  69 
  70     private static String CP_SEPARATOR = Platform.isWindows() ?  ";" : ":";
  71 
  72     public static void buildTestModule() throws Exception {
  73 
  74         // javac -d mods/$TESTMODULE src/$TESTMODULE/**
  75         JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE),
  76                                  MODS_DIR.resolve(TEST_MODULE),
  77                                  null);
  78 
  79         // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
  80         JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE),
  81                                  MODS_DIR.resolve(MAIN_MODULE),
  82                                  MODS_DIR.toString());
  83 
  84         libsDir = Files.createTempDirectory(USER_DIR, PATH_LIBS);
  85         mainJar = libsDir.resolve(MAIN_MODULE + ".jar");
  86         testJar = libsDir.resolve(TEST_MODULE + ".jar");
  87 
  88         // modylibs contains both modules com.foos.jar, com.bars.jar
  89         // build com.foos.jar
  90         String classes = MODS_DIR.resolve(TEST_MODULE).toString();
  91         JarBuilder.createModularJar(testJar.toString(), classes, TEST_CLASS);
  92 
  93         // build com.bars.jar
  94         classes = MODS_DIR.resolve(MAIN_MODULE).toString();
  95         JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
  96         System.out.println("mainJar = " + mainJar.toString());
  97     }
  98 
  99     public static void main(String... args) throws Exception {
 100         runWithModulePath();
 101         runWithJarPath();
 102     }
 103 
 104     private static void tty(String... args) {
 105         for (String s : args) {
 106             System.out.print(s + " ");
 107         }
 108         System.out.print("\n");
 109     }
 110 
 111     public static void runWithModulePath(String... extraRuntimeArgs) throws Exception {
 112         // compile the modules and create the modular jar files
 113         buildTestModule();
 114         String appClasses[] = {MAIN_CLASS, TEST_CLASS};
 115         // create an archive with the classes in the modules built in the
 116         // previous step
 117         OutputAnalyzer output = TestCommon.createArchive(
 118                                         null, appClasses,
 119                                         "--module-path",
 120                                         libsDir.toString(), 
 121                                         "-m", MAIN_MODULE);
 122         TestCommon.checkDump(output);
 123 
 124         // following 1 - 4 test with CDS off
 125         tty("1. run with CDS off");
 126         TestCommon.execOff( "-p", libsDir.toString(),
 127                             "-m", MAIN_MODULE)
 128             .shouldHaveExitValue(0)
 129             .shouldNotContain(OPTIMIZE_ENABLED)
 130             .shouldContain(CLASS_FOUND_MESSAGE);
 131         tty("2. run with CDS off, without module path");
 132         TestCommon.execOff("-cp",
 133                            mainJar.toString(),
 134                            MAIN_CLASS)
 135             .shouldHaveExitValue(0)
 136             .shouldContain(CLASS_NOT_FOUND_MESSAGE);
 137         tty("3. run with CDS off, but with full jars in path");
 138         TestCommon.execOff( "-cp", mainJar.toString() + CP_SEPARATOR + testJar.toString(),
 139                             MAIN_CLASS)
 140             .shouldHaveExitValue(0)
 141             .shouldNotContain(OPTIMIZE_ENABLED)
 142             .shouldContain(CLASS_FOUND_MESSAGE);
 143         tty("4. run with CDS off, only main jar on path, but given moudle path");
 144         TestCommon.execOff( "-cp", mainJar.toString(),
 145                             "--module-path", libsDir.toString(),
 146                             "--add-modules", TEST_MODULE,
 147                             MAIN_CLASS)
 148             .shouldHaveExitValue(0) 
 149             .shouldNotContain(OPTIMIZE_ENABLED)
 150             .shouldContain(CLASS_FOUND_MESSAGE);
 151 
 152         // Following 5 - 10 test woith CDS on
 153         tty("5. run with CDS on, with module path");
 154         String prefix[] = {"-Djava.class.path=", "-Xlog:cds"};
 155         TestCommon.runWithModules(prefix,
 156                                  null,               // --upgrade-module-path
 157                                  libsDir.toString(), // --module-path
 158                                  MAIN_MODULE)        // -m
 159             .assertNormalExit(out -> {
 160                 out.shouldNotContain(OPTIMIZE_ENABLED)
 161                    .shouldContain(OPTIMIZE_DISABLED)
 162                    .shouldContain(CLASS_FOUND_MESSAGE);
 163             });
 164         tty("6. run with CDS on, with module paths set correctly");
 165         TestCommon.run("-Xlog:cds",
 166                        "-p", libsDir.toString(),
 167                        "-m", MAIN_MODULE)
 168             .assertNormalExit(out -> {
 169                 out.shouldContain(CLASS_FOUND_MESSAGE)
 170                    .shouldContain(OPTIMIZE_DISABLED)
 171                    .shouldNotContain(OPTIMIZE_ENABLED);
 172             });
 173         tty("7. run with CDS on, with jar on path");
 174         TestCommon.run("-Xlog:cds",
 175                        "-cp", mainJar + CP_SEPARATOR + testJar,
 176                        MAIN_CLASS)
 177             .assertNormalExit(out -> {
 178                 out.shouldContain(CLASS_FOUND_MESSAGE)
 179                    .shouldContain(OPTIMIZE_DISABLED)
 180                    .shouldNotContain(OPTIMIZE_ENABLED);
 181             });
 182 
 183         tty("8. run with CDS on, with --module-path, with jar should fail");
 184         TestCommon.run("-Xlog:cds",
 185                        "-p", libsDir.toString(),
 186                        "-cp", mainJar.toString(),
 187                        MAIN_CLASS)
 188             .assertNormalExit(out -> {
 189                 out.shouldContain(CLASS_NOT_FOUND_MESSAGE)
 190                    .shouldNotContain(OPTIMIZE_ENABLED);
 191             });
 192         tty("9. run with CDS on, with com.foos on  --module-path, with main jar on cp should pass");
 193         TestCommon.run("-Xlog:cds",
 194                        "--module-path", libsDir.toString(),
 195                        "--add-modules", TEST_MODULE,
 196                        "-cp", mainJar.toString(),
 197                        MAIN_CLASS)
 198             .assertNormalExit(out -> {
 199                 out.shouldContain(CLASS_FOUND_MESSAGE)
 200                    .shouldNotContain(OPTIMIZE_ENABLED);
 201             });
 202         tty("10. run with CDS on, --module-path, with -Xbootclasspath/a: .");
 203         TestCommon.run("-Xlog:cds",
 204                        "-Xbootclasspath/a:", ".",
 205                        "--module-path", libsDir.toString(),
 206                        MAIN_CLASS)
 207             .assertAbnormalExit(out -> {
 208                 out.shouldNotContain(CLASS_FOUND_MESSAGE)
 209                    .shouldContain(OPTIMIZE_DISABLED)           // mapping info
 210                    .shouldContain("shared class paths mismatch");
 211             });
 212     }
 213 
 214     public static void runWithJarPath(String... extraRuntimeArgs) throws Exception {
 215         // compile the modules and create the modular jar files
 216         buildTestModule();
 217         String appClasses[] = {MAIN_CLASS, TEST_CLASS};
 218         // create an archive with the classes in the modules built in the
 219         // previous step
 220         OutputAnalyzer output = TestCommon.createArchive(
 221                                         null, appClasses,
 222                                         "-cp",
 223                                         testJar.toString() + CP_SEPARATOR + mainJar.toString(), 
 224                                         MAIN_CLASS);
 225         TestCommon.checkDump(output);
 226 
 227         // tests 1 - 4 test with CDS off are same as with module archive.
 228         tty("tests 1 - 4 test with CDS off are same as with module archive, skipped");
 229    
 230         // Following 5 - 10 test with CDS on
 231         tty("5. run with CDS on, with module path");
 232         String prefix[] = {"-Djava.class.path=", "-Xlog:cds"};
 233         TestCommon.runWithModules(prefix,
 234                                  null,               // --upgrade-module-path
 235                                  libsDir.toString(), // --module-path
 236                                  MAIN_MODULE)        // -m
 237             .assertAbnormalExit(out -> {
 238                 out.shouldNotContain(OPTIMIZE_ENABLED)
 239                    .shouldNotContain(CLASS_FOUND_MESSAGE);
 240             });
 241         tty("6. run with CDS on, with module paths set correctly");
 242         TestCommon.run("-Xlog:cds",
 243                        "-p", libsDir.toString(),
 244                        "-m", MAIN_MODULE)
 245             .assertAbnormalExit(out -> {
 246                 out.shouldNotContain(CLASS_FOUND_MESSAGE)
 247                    .shouldNotContain(OPTIMIZE_ENABLED);
 248             });
 249         tty("7. run with CDS on, with jar on path");
 250         TestCommon.run("-Xlog:cds",
 251                        "-cp", testJar.toString() + CP_SEPARATOR + mainJar.toString(),
 252                        MAIN_CLASS)
 253             .assertNormalExit(out -> {
 254                 out.shouldContain(CLASS_FOUND_MESSAGE)
 255                    .shouldContain(OPTIMIZE_ENABLED);
 256             });
 257         tty("8. run with CDS on, with --module-path, with jars on classpath should fail");
 258         TestCommon.run("-Xlog:cds",
 259                        "-p", libsDir.toString(),
 260                        "-cp", testJar.toString() + CP_SEPARATOR + mainJar.toString(),
 261                        MAIN_CLASS)
 262             .assertNormalExit(out -> {
 263                 out.shouldNotContain(CLASS_NOT_FOUND_MESSAGE)
 264                    .shouldContain(CLASS_FOUND_MESSAGE)
 265                    .shouldNotContain(OPTIMIZE_ENABLED);
 266             });
 267         tty("9. run with CDS on,  with main jar only on classpath should not pass");
 268         TestCommon.run("-Xlog:cds",
 269                        "-cp", mainJar.toString(),
 270                        MAIN_CLASS)
 271             .assertAbnormalExit(out -> {
 272                 out.shouldNotContain(CLASS_FOUND_MESSAGE)
 273                    .shouldNotContain(CLASS_NOT_FOUND_MESSAGE)
 274                    .shouldNotContain(OPTIMIZE_ENABLED)
 275                    .shouldNotContain(OPTIMIZE_DISABLED)
 276                    .shouldContain("shared class paths mismatch");
 277             });
 278         tty("10. run with CDS on,  with main/test jars on classpath also with -Xbootclasspath/a:  should not pass");
 279         TestCommon.run("-Xlog:cds",
 280                        "-cp", mainJar.toString() + CP_SEPARATOR + testJar.toString(),
 281                        "-Xbootclasspath/a:", ".",
 282                        MAIN_CLASS)
 283             .assertAbnormalExit(out -> {
 284                 out.shouldNotContain(CLASS_FOUND_MESSAGE)
 285                    .shouldNotContain(CLASS_NOT_FOUND_MESSAGE)
 286                    .shouldContain(OPTIMIZE_DISABLED)
 287                    .shouldNotContain(OPTIMIZE_ENABLED)
 288                    .shouldContain("shared class paths mismatch");
 289             });
 290     }
 291 }