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 import java.io.IOException;
  25 import java.io.PrintWriter;
  26 import java.io.StringWriter;
  27 import java.lang.module.ModuleDescriptor;
  28 import java.lang.reflect.Layer;
  29 import java.nio.file.Files;
  30 import java.nio.file.Path;
  31 import java.nio.file.Paths;
  32 import java.util.ArrayList;
  33 import java.util.Collections;
  34 import java.util.List;
  35 import java.util.stream.Stream;
  36 
  37 import jdk.tools.jlink.plugin.Plugin;
  38 import jdk.tools.jlink.internal.PluginRepository;
  39 import tests.Helper;
  40 import tests.JImageGenerator;
  41 import tests.JImageGenerator.InMemoryFile;
  42 
  43 /*
  44  * @test
  45  * @summary Test image creation
  46  * @author Jean-Francois Denise
  47  * @library ../lib
  48  * @modules java.base/jdk.internal.jimage
  49  *          jdk.jdeps/com.sun.tools.classfile
  50  *          jdk.jlink/jdk.tools.jlink.internal
  51  *          jdk.jlink/jdk.tools.jmod
  52  *          jdk.jlink/jdk.tools.jimage
  53  *          jdk.compiler
  54  * @build tests.*
  55  * @run main/othervm -Xmx1g JLinkTest
  56  */
  57 public class JLinkTest {
  58     // number of built-in plugins from jdk.jlink module
  59     private static int getNumJlinkPlugins() {
  60         ModuleDescriptor desc = Plugin.class.getModule().getDescriptor();
  61         return desc.provides().
  62                     get(Plugin.class.getName()).
  63                     providers().size();
  64     }
  65 
  66     private static boolean isOfJLinkModule(Plugin p) {
  67         return p.getClass().getModule() == Plugin.class.getModule();
  68     }
  69 
  70     public static void main(String[] args) throws Exception {
  71 
  72         Helper helper = Helper.newHelper();
  73         if (helper == null) {
  74             System.err.println("Test not run");
  75             return;
  76         }
  77         helper.generateDefaultModules();
  78         // expected num. of plugins from jdk.jlink module
  79         int expectedJLinkPlugins = getNumJlinkPlugins();
  80         int totalPlugins = 0;
  81         {
  82             // number of built-in plugins
  83             List<Plugin> builtInPlugins = new ArrayList<>();
  84             builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot()));
  85             totalPlugins = builtInPlugins.size();
  86             // actual num. of plugins loaded from jdk.jlink module
  87             int actualJLinkPlugins = 0;
  88             for (Plugin p : builtInPlugins) {
  89                 p.getState();
  90                 p.getType();
  91                 if (isOfJLinkModule(p)) {
  92                     actualJLinkPlugins++;
  93                 }
  94             }
  95             if (expectedJLinkPlugins != actualJLinkPlugins) {
  96                 throw new AssertionError("Actual plugins loaded from jdk.jlink: " +
  97                         actualJLinkPlugins + " which doesn't match expected number : " +
  98                         expectedJLinkPlugins);
  99             }
 100         }
 101 
 102         {
 103             String moduleName = "bug8134651";
 104             JImageGenerator.getJLinkTask()
 105                     .modulePath(helper.defaultModulePath())
 106                     .output(helper.createNewImageDir(moduleName))
 107                     .addMods("leaf1")
 108                     .option("")
 109                     .call().assertSuccess();
 110             JImageGenerator.getJLinkTask()
 111                     .modulePath(helper.defaultModulePath())
 112                     .addMods("leaf1")
 113                     .option("--output")
 114                     .option("")
 115                     .call().assertFailure("Error: no value given for --output");
 116             JImageGenerator.getJLinkTask()
 117                     .modulePath("")
 118                     .output(helper.createNewImageDir(moduleName))
 119                     .addMods("leaf1")
 120                     .option("")
 121                     .call().assertFailure("Error: no value given for --modulepath");
 122         }
 123 
 124         {
 125             String moduleName = "filter";
 126             Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
 127             String className = "_A.class";
 128             JImageGenerator.addFiles(jmod, new InMemoryFile(className, new byte[0]));
 129             Path image = helper.generateDefaultImage(moduleName).assertSuccess();
 130             helper.checkImage(image, moduleName, new String[] {"/" + moduleName + "/" + className}, null);
 131         }
 132 
 133         {
 134             // Help
 135             StringWriter writer = new StringWriter();
 136             jdk.tools.jlink.internal.Main.run(new String[]{"--help"}, new PrintWriter(writer));
 137             String output = writer.toString();
 138             if (output.split("\n").length < 10) {
 139                 System.err.println(output);
 140                 throw new AssertionError("Help");
 141             }
 142         }
 143 
 144         {
 145             // License files
 146             String copied = "LICENSE";
 147             String[] arr = copied.split(",");
 148             String[] copyFiles = new String[2];
 149             copyFiles[0] = "--copy-files";
 150             copyFiles[1] = copied;
 151             Path imageDir = helper.generateDefaultImage(copyFiles, "composite2").assertSuccess();
 152             helper.checkImage(imageDir, "composite2", null, null, arr);
 153         }
 154 
 155         {
 156             // List plugins
 157             StringWriter writer = new StringWriter();
 158             jdk.tools.jlink.internal.Main.run(new String[]{"--list-plugins"}, new PrintWriter(writer));
 159             String output = writer.toString();
 160             long number = Stream.of(output.split("\\R"))
 161                     .filter((s) -> s.matches("Plugin Name:.*"))
 162                     .count();
 163             if (number != totalPlugins) {
 164                 System.err.println(output);
 165                 throw new AssertionError("Found: " + number + " expected " + totalPlugins);
 166             }
 167         }
 168 
 169         // filter out files and resources + Skip debug + compress
 170         {
 171             String[] userOptions = {"--compress", "2", "--strip-debug",
 172                 "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files",
 173                 "*" + Helper.getDebugSymbolsExtension()};
 174             String moduleName = "excludezipskipdebugcomposite2";
 175             helper.generateDefaultJModule(moduleName, "composite2");
 176             String[] res = {".jcov", "/META-INF/"};
 177             String[] files = {Helper.getDebugSymbolsExtension()};
 178             Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
 179             helper.checkImage(imageDir, moduleName, res, files);
 180         }
 181 
 182         // filter out + Skip debug + compress with filter + sort resources
 183         {
 184             String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*",
 185                 "--strip-debug", "--exclude-resources",
 186                 "*.jcov, */META-INF/*", "--order-resources",
 187                 "*/module-info.class,/sortcomposite2/*,*/javax/management/*"};
 188             String moduleName = "excludezipfilterskipdebugcomposite2";
 189             helper.generateDefaultJModule(moduleName, "composite2");
 190             String[] res = {".jcov", "/META-INF/"};
 191             Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess();
 192             helper.checkImage(imageDir, moduleName, res, null);
 193         }
 194 
 195         // default compress
 196         {
 197             testCompress(helper, "compresscmdcomposite2", "--compress", "2");
 198         }
 199 
 200         {
 201             testCompress(helper, "compressfiltercmdcomposite2",
 202                     "--compress=2:filter=^/java.base/java/lang/*");
 203         }
 204 
 205         // compress 0
 206         {
 207             testCompress(helper, "compress0filtercmdcomposite2",
 208                     "--compress=0:filter=^/java.base/java/lang/*");
 209         }
 210 
 211         // compress 1
 212         {
 213             testCompress(helper, "compress1filtercmdcomposite2",
 214                     "--compress=1:filter=^/java.base/java/lang/*");
 215         }
 216 
 217         // compress 2
 218         {
 219             testCompress(helper, "compress2filtercmdcomposite2",
 220                     "--compress=2:filter=^/java.base/java/lang/*");
 221         }
 222 
 223         // invalid compress level
 224         {
 225             String[] userOptions = {"--compress", "invalid"};
 226             String moduleName = "invalidCompressLevel";
 227             helper.generateDefaultJModule(moduleName, "composite2");
 228             helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid");
 229         }
 230 
 231         // @file
 232         {
 233             Path path = Paths.get("embedded.properties");
 234             Files.write(path, Collections.singletonList("--strip-debug --addmods " +
 235                     "toto.unknown --compress UNKNOWN\n"));
 236             String[] userOptions = {"@", path.toAbsolutePath().toString()};
 237             String moduleName = "configembeddednocompresscomposite2";
 238             helper.generateDefaultJModule(moduleName, "composite2");
 239             Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
 240             helper.checkImage(imageDir, moduleName, null, null);
 241         }
 242 
 243     }
 244 
 245     private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException {
 246         helper.generateDefaultJModule(moduleName, "composite2");
 247         Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
 248         helper.checkImage(imageDir, moduleName, null, null);
 249     }
 250 }