1 /*
   2  * Copyright (c) 2015, 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  * @test
  26  * @summary Test image creation
  27  * @author Jean-Francois Denise
  28  * @library ../lib
  29  * @modules java.base/jdk.internal.jimage
  30  *          jdk.jdeps/com.sun.tools.classfile
  31  *          jdk.jlink/jdk.tools.jlink
  32  *          jdk.jlink/jdk.tools.jlink.internal
  33  *          jdk.jlink/jdk.tools.jmod
  34  *          jdk.jlink/jdk.tools.jimage
  35  *          jdk.compiler
  36  * @build tests.*
  37  * @run main/othervm -verbose:gc -Xmx1g JLink2Test
  38  */
  39 
  40 import java.io.File;
  41 import java.io.FileOutputStream;
  42 import java.io.IOException;
  43 import java.nio.file.Files;
  44 import java.nio.file.Path;
  45 import java.util.ArrayList;
  46 import java.util.Arrays;
  47 import java.util.Collections;
  48 import java.util.List;
  49 import java.util.jar.JarEntry;
  50 import java.util.jar.JarOutputStream;
  51 
  52 import jdk.tools.jlink.plugins.DefaultImageBuilderProvider;
  53 import jdk.tools.jlink.internal.ImagePluginConfiguration;
  54 import tests.Helper;
  55 import tests.JImageGenerator;
  56 import tests.JImageValidator;
  57 
  58 public class JLink2Test {
  59 
  60     public static void main(String[] args) throws Exception {
  61         Helper helper = Helper.newHelper();
  62         if (helper == null) {
  63            System.err.println("Test not run");
  64             return;
  65         }
  66         helper.generateDefaultModules();
  67 
  68         testSameNames(helper);
  69         testBomFile(helper);
  70         testFileReplacement(helper);
  71         testModulePath(helper);
  72     }
  73 
  74     private static void testModulePath(Helper helper) throws IOException {
  75         Path unknownDir = helper.createNewImageDir("jar");
  76         Path jar = helper.getJarDir().resolve("bad.jar");
  77         JImageGenerator.getJLinkTask()
  78                 .pluginModulePath(unknownDir)
  79                 .option("--help")
  80                 .call().assertFailure("(\n|\r|.)*Error: java.nio.file.NoSuchFileException: .*jar.image(\n|\r|.)*");
  81         Files.createFile(jar);
  82         JImageGenerator.getJLinkTask()
  83                 .pluginModulePath(jar)
  84                 .option("--help")
  85                 .call().assertFailure("(\n|\r|.)*Error: java.nio.file.NotDirectoryException: .*bad.jar(\n|\r|.)*");
  86         JImageGenerator.getJLinkTask()
  87                 .pluginModulePath(jar.getParent())
  88                 .option("--help")
  89                 .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
  90         try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) {
  91             JarEntry entry = new JarEntry("class");
  92             out.putNextEntry(entry);
  93             out.write("AAAA".getBytes());
  94             out.closeEntry();
  95         }
  96         JImageGenerator.getJLinkTask()
  97                 .pluginModulePath(jar.getParent())
  98                 .output(helper.createNewImageDir("crash"))
  99                 .addJmods(helper.getStdJmodsDir())
 100                 .addJmods(jar.getParent())
 101                 .addMods("bad")
 102                 .call().assertFailure("Error: java.io.IOException: module-info not found for bad");
 103         try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) {
 104             JarEntry entry = new JarEntry("classes");
 105             out.putNextEntry(entry);
 106             out.closeEntry();
 107 
 108             entry = new JarEntry("classes/class");
 109             out.putNextEntry(entry);
 110             out.write("AAAA".getBytes());
 111             out.closeEntry();
 112         }
 113         JImageGenerator.getJLinkTask()
 114                 .pluginModulePath(jar.getParent())
 115                 .output(helper.createNewImageDir("bad"))
 116                 .addJmods(jar.getParent())
 117                 .addJars(helper.getStdJmodsDir())
 118                 .addMods("bad")
 119                 .call().assertFailure("Error: java.io.IOException: module-info not found for bad");
 120     }
 121 
 122     private static void testSameNames(Helper helper) throws Exception {
 123         // Multiple modules with the same name in modulepath, take the first one in the path.
 124         // First jmods then jars. So jmods are found, jars are hidden.
 125         String[] jarClasses = {"amodule.jar.Main"};
 126         String[] jmodsClasses = {"amodule.jmods.Main"};
 127         helper.generateDefaultJarModule("amodule", Arrays.asList(jarClasses));
 128         helper.generateDefaultJModule("amodule", Arrays.asList(jmodsClasses));
 129         List<String> okLocations = new ArrayList<>();
 130         okLocations.addAll(Helper.toLocation("amodule", Arrays.asList(jmodsClasses)));
 131         Path image = helper.generateDefaultImage(new String[0], "amodule").assertSuccess();
 132         JImageValidator validator = new JImageValidator("amodule", okLocations,
 133                  image.toFile(), Collections.emptyList(), Collections.emptyList());
 134         validator.validate();
 135     }
 136 
 137     private static void testBomFile(Helper helper) throws Exception {
 138         File defaults = new File("embedded.properties");
 139         Files.write(defaults.toPath(), ("jdk.jlink.defaults=--genbom --exclude-resources *.jcov,*/META-INF/*" +
 140                 " --addmods UNKNOWN\n").getBytes());
 141         String[] userOptions = {"--zip",
 142             "*",                "--strip-java-debug", "on",
 143                 "--configuration", defaults.getAbsolutePath()};
 144         String moduleName = "bomzip";
 145         helper.generateDefaultJModule(moduleName, "composite2");
 146         Path imgDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
 147         helper.checkImage(imgDir, moduleName, userOptions, null, null);
 148         File bom = new File(imgDir.toFile(), "bom");
 149         if (!bom.exists()) {
 150             throw new RuntimeException(bom.getAbsolutePath() + " not generated");
 151         }
 152         String bomcontent = new String(Files.readAllBytes(bom.toPath()));
 153         if (!bomcontent.contains("--strip-java-debug")
 154                 || !bomcontent.contains("--zip")
 155                 || !bomcontent.contains("*")
 156                 || !bomcontent.contains("--genbom")
 157                 || !bomcontent.contains("zip")
 158                 || !bomcontent.contains("--exclude-resources *.jcov,"
 159                         + "*/META-INF/*")
 160                 || !bomcontent.contains("--configuration")
 161                 || !bomcontent.contains(defaults.getAbsolutePath())
 162                 || !bomcontent.contains("--addmods UNKNOWN")) {
 163             throw new Exception("Not expected content in " + bom);
 164         }
 165     }
 166 
 167     private static void testFileReplacement(Helper helper) throws Exception {
 168         // Replace jvm.cfg and jvm.hprof.txt with some content
 169         // having an header to check against
 170         String header = "# YOU SHOULD FIND ME\n";
 171         File jvmcfg = new File(System.getProperty("java.home")
 172                 + File.separator + "lib" + File.separator + "jvm.cfg");
 173         File jvmhprof = new File(System.getProperty("java.home")
 174                 + File.separator + "lib" + File.separator + "jvm.hprof.txt");
 175         if (jvmcfg.exists() && jvmhprof.exists()) {
 176             String cfgcontent = header + new String(Files.readAllBytes(jvmcfg.toPath()));
 177             File cfgNewContent = File.createTempFile("jvmcfgtest", null);
 178             cfgNewContent.deleteOnExit();
 179             Files.write(cfgNewContent.toPath(), cfgcontent.getBytes());
 180 
 181             String hprofcontent = header + new String(Files.readAllBytes(jvmhprof.toPath()));
 182             File hprofNewContent = File.createTempFile("hproftest", null);
 183             hprofNewContent.deleteOnExit();
 184             Files.write(hprofNewContent.toPath(), hprofcontent.getBytes());
 185 
 186             String[] userOptions = {"--replace-file",
 187                 "/java.base/native/jvm.cfg,"
 188                 + cfgNewContent.getAbsolutePath()
 189                 + ",/jdk.hprof.agent/native/jvm.hprof.txt,"
 190                 + hprofNewContent.getAbsolutePath()};
 191             String moduleName = "jvmcfg";
 192             helper.generateDefaultJModule(moduleName, "composite2", "jdk.hprof.agent");
 193             Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
 194             helper.checkImage(imageDir, moduleName, null, null);
 195             Path jvmcfg2 = imageDir.resolve("lib").resolve("jvm.cfg");
 196             checkFile(header, jvmcfg2);
 197 
 198             Path hprof2 = imageDir.resolve("lib").resolve("jvm.hprof.txt");
 199             checkFile(header, hprof2);
 200         } else {
 201             System.err.println("Warning, jvm.cfg or jvm.hprof.txt files not found, "
 202                     + "file replacement not checked");
 203         }
 204     }
 205 
 206     private static void checkFile(String header, Path file) throws IOException {
 207         if (!Files.exists(file)) {
 208             throw new RuntimeException(file.toAbsolutePath() +" not generated");
 209         }
 210         String content = new String(Files.readAllBytes(file));
 211         if (!content.startsWith(header)) {
 212             throw new AssertionError("jvm.cfg not replaced with "
 213                     + "expected content");
 214         }
 215     }
 216 
 217 }