1 /*
   2  * Copyright (c) 2019, 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  * @summary A few edge cases where there's no class to be included in the dynamic archive.
  28  * @requires vm.cds
  29  * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
  30  * @build StrConcatApp
  31  * @run driver ClassFileInstaller -jar strConcatApp.jar StrConcatApp
  32  * @run driver NoClassToArchive
  33  */
  34 
  35 import java.io.File;
  36 import jdk.test.lib.process.OutputAnalyzer;
  37 import jdk.test.lib.process.ProcessTools;
  38 
  39 public class NoClassToArchive extends DynamicArchiveTestBase {
  40     static final String warningMessage =
  41         "There is no class to be included in the dynamic archive";
  42     static final String classList = System.getProperty("test.classes") +
  43         File.separator + "NoClassToArchive.list";
  44     static final String appClass = "StrConcatApp";
  45 
  46     public static void main(String[] args) throws Exception {
  47         runTest(NoClassToArchive::testDefaultBase);
  48         runTest(NoClassToArchive::testCustomBase);
  49     }
  50 
  51     // (1) Test with default base archive + top archive
  52     static void testDefaultBase() throws Exception {
  53         String topArchiveName = getNewArchiveName("top");
  54         doTest(null, topArchiveName);
  55     }
  56 
  57     // (2) Test with custom base archive + top archive
  58     static void testCustomBase() throws Exception {
  59         String topArchiveName = getNewArchiveName("top2");
  60         String baseArchiveName = getNewArchiveName("base");
  61         doTestCustomBase(baseArchiveName, topArchiveName);
  62     }
  63 
  64     private static void checkWarning(OutputAnalyzer output) throws Exception {
  65         if (output.getStdout().contains("jrt:/") || output.getStdout().contains("unsafe anonymous")) {
  66             System.out.println("test skipped: this platform uses non-archived classes when running -version");
  67         } else {
  68             output.shouldContain(warningMessage);
  69         }
  70     }
  71 
  72     private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
  73         dump2(baseArchiveName, topArchiveName,
  74              "-Xlog:cds",
  75              "-Xlog:cds+dynamic=debug",
  76              "-Xlog:class+load=trace",
  77              "-version")
  78             .assertNormalExit(output -> checkWarning(output));
  79 
  80         dump2(baseArchiveName, topArchiveName,
  81              "-Xlog:cds",
  82              "-Xlog:cds+dynamic=debug",
  83              "-Xlog:class+load=trace",
  84              "-help")
  85             .assertNormalExit(output -> {
  86                     // some classes will be loaded from the java.base module
  87                     output.shouldContain("java.text.MessageFormat source: jrt:/java.base");
  88                 });
  89     }
  90 
  91     private static void doTestCustomBase(String baseArchiveName, String topArchiveName) throws Exception {
  92         String appJar = ClassFileInstaller.getJarPath("strConcatApp.jar");
  93         // dump class list by running the StrConcatApp
  94         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
  95             true,
  96             "-XX:DumpLoadedClassList=" + classList,
  97             "-cp",
  98             appJar,
  99             appClass);
 100         OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
 101         TestCommon.checkExecReturn(output, 0, true, "length = 0");
 102 
 103         // create a custom base archive based on the class list
 104         dumpBaseArchive(baseArchiveName, "-XX:SharedClassListFile=" + classList);
 105 
 106         // create a dynamic archive with the custom base archive
 107         // no class should be included in the dynamic archive
 108         dump2(baseArchiveName, topArchiveName,
 109               "-Xlog:cds",
 110               "-Xlog:cds+dynamic=debug",
 111               "-Xlog:class+load=trace",
 112               "-version")
 113             .assertNormalExit(out -> checkWarning(out));
 114     }
 115 }