1 /*
   2  * Copyright (c) 2016, 2017, 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.File;
  25 import java.io.IOException;
  26 import java.lang.module.ModuleDescriptor;
  27 import java.lang.reflect.Layer;
  28 import java.nio.file.Files;
  29 import java.nio.file.Path;
  30 import java.nio.file.Paths;
  31 import java.util.Arrays;
  32 import java.util.Set;
  33 import java.util.spi.ToolProvider;
  34 import java.util.stream.Collectors;
  35 import java.util.stream.Stream;
  36 
  37 import jdk.testlibrary.FileUtils;
  38 
  39 import static jdk.testlibrary.ProcessTools.*;
  40 
  41 
  42 import org.testng.annotations.BeforeTest;
  43 import org.testng.annotations.Test;
  44 import static org.testng.Assert.*;
  45 
  46 /**
  47  * @test
  48  * @bug 8142968 8173381 8174740
  49  * @library /lib/testlibrary
  50  * @modules jdk.compiler jdk.jlink
  51  * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
  52  * @run testng UserModuleTest
  53  */
  54 
  55 public class UserModuleTest {
  56     private static final String JAVA_HOME = System.getProperty("java.home");
  57     private static final String TEST_SRC = System.getProperty("test.src");
  58 
  59     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  60     private static final Path MODS_DIR = Paths.get("mods");
  61     private static final Path JMODS_DIR = Paths.get("jmods");
  62 
  63     private static final Path IMAGE = Paths.get("image");
  64     private static final String MAIN_MID = "m1/p1.Main";
  65 
  66     // the names of the modules in this test
  67     private static String[] modules = new String[] {"m1", "m2", "m3", "m4"};
  68 
  69 
  70     private static boolean hasJmods() {
  71         if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
  72             System.err.println("Test skipped. NO jmods directory");
  73             return false;
  74         }
  75         return true;
  76     }
  77 
  78     /*
  79      * Compiles all modules used by the test
  80      */
  81     @BeforeTest
  82     public void compileAll() throws Throwable {
  83         if (!hasJmods()) return;
  84 
  85         for (String mn : modules) {
  86             Path msrc = SRC_DIR.resolve(mn);
  87             assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
  88                 "--module-source-path", SRC_DIR.toString()));
  89         }
  90 
  91         if (Files.exists(IMAGE)) {
  92             FileUtils.deleteFileTreeUnchecked(IMAGE);
  93         }
  94 
  95         createImage(IMAGE, "m1", "m3");
  96 
  97         createJmods("m1", "m4");
  98     }
  99 
 100     /*
 101      * Test the image created when linking with a module with
 102      * no Packages attribute
 103      */
 104     @Test
 105     public void testPackagesAttribute() throws Throwable {
 106         if (!hasJmods()) return;
 107 
 108         Path java = IMAGE.resolve("bin").resolve("java");
 109         assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
 110                         .outputTo(System.out)
 111                         .errorTo(System.out)
 112                         .getExitValue() == 0);
 113     }
 114 
 115     /*
 116      * Test the image created when linking with an open module
 117     */
 118     @Test
 119     public void testOpenModule() throws Throwable {
 120         if (!hasJmods()) return;
 121 
 122         Path java = IMAGE.resolve("bin").resolve("java");
 123         assertTrue(executeProcess(java.toString(), "-m", "m3/p3.Main")
 124                         .outputTo(System.out)
 125                         .errorTo(System.out)
 126                         .getExitValue() == 0);
 127     }
 128 
 129     /*
 130      * Disable the fast loading of system modules.
 131      * Parsing module-info.class
 132      */
 133     @Test
 134     public void disableSystemModules() throws Throwable {
 135         if (!hasJmods()) return;
 136 
 137         Path java = IMAGE.resolve("bin").resolve("java");
 138         assertTrue(executeProcess(java.toString(),
 139                                   "-Djdk.system.module.finder.disabledFastPath",
 140                                   "-m", MAIN_MID)
 141                         .outputTo(System.out)
 142                         .errorTo(System.out)
 143                         .getExitValue() == 0);
 144     }
 145 
 146     /*
 147      * Test the optimization that deduplicates Set<String> on targets of exports,
 148      * uses, provides.
 149      */
 150     @Test
 151     public void testDedupSet() throws Throwable {
 152         if (!hasJmods()) return;
 153 
 154         Path dir = Paths.get("dedupSetTest");
 155         createImage(dir, "m1", "m2", "m3", "m4");
 156         Path java = dir.resolve("bin").resolve("java");
 157         assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
 158                         .outputTo(System.out)
 159                         .errorTo(System.out)
 160                         .getExitValue() == 0);
 161     }
 162 
 163     private void createJmods(String... modules) throws IOException {
 164         // use the same target platform as in java.base
 165         ModuleDescriptor md = Layer.boot().findModule("java.base").get()
 166                                    .getDescriptor();
 167         String osName = md.osName().get();
 168         String osArch = md.osArch().get();
 169 
 170         // create JMOD files
 171         Files.createDirectories(JMODS_DIR);
 172         Stream.of(modules).forEach(mn ->
 173             assertTrue(jmod("create",
 174                 "--class-path", MODS_DIR.resolve(mn).toString(),
 175                 "--os-name", osName,
 176                 "--os-arch", osArch,
 177                 "--main-class", mn.replace('m', 'p') + ".Main",
 178                 JMODS_DIR.resolve(mn + ".jmod").toString()) == 0)
 179         );
 180     }
 181 
 182 
 183     /**
 184      * Verify the module descriptor if package p4.dummy is excluded at link time.
 185      */
 186     @Test
 187     public void testModulePackagesAttribute() throws Throwable {
 188         if (!hasJmods()) return;
 189 
 190         // create an image using JMOD files
 191         Path dir = Paths.get("packagesTest");
 192         String mp = Paths.get(JAVA_HOME, "jmods").toString() +
 193             File.pathSeparator + JMODS_DIR.toString();
 194 
 195         Set<String> modules = Set.of("m1", "m4");
 196         assertTrue(JLINK_TOOL.run(System.out, System.out,
 197             "--output", dir.toString(),
 198             "--exclude-resources", "m4/p4/dummy/*",
 199             "--add-modules", modules.stream().collect(Collectors.joining(",")),
 200             "--module-path", mp) == 0);
 201 
 202         // verify ModuleDescriptor
 203         Path java = dir.resolve("bin").resolve("java");
 204         assertTrue(executeProcess(java.toString(),
 205                         "--add-modules=m1", "-m", "m4")
 206             .outputTo(System.out)
 207             .errorTo(System.out)
 208             .getExitValue() == 0);
 209     }
 210 
 211     /**
 212      * Verify the plugin to retain ModuleTarget attribute
 213      */
 214     @Test
 215     public void testRetainModuleTarget() throws Throwable {
 216         if (!hasJmods()) return;
 217 
 218         // create an image using JMOD files
 219         Path dir = Paths.get("retainModuleTargetTest");
 220         String mp = Paths.get(JAVA_HOME, "jmods").toString() +
 221             File.pathSeparator + JMODS_DIR.toString();
 222 
 223         Set<String> modules = Set.of("m1", "m4");
 224         assertTrue(JLINK_TOOL.run(System.out, System.out,
 225             "--output", dir.toString(),
 226             "--system-modules", "retainModuleTarget",
 227             "--exclude-resources", "m4/p4/dummy/*",
 228             "--add-modules", modules.stream().collect(Collectors.joining(",")),
 229             "--module-path", mp) == 0);
 230 
 231         // verify ModuleDescriptor
 232         Path java = dir.resolve("bin").resolve("java");
 233         assertTrue(executeProcess(java.toString(),
 234                         "--add-modules=m1", "-m", "m4", "retainModuleTarget")
 235             .outputTo(System.out)
 236             .errorTo(System.out)
 237             .getExitValue() == 0);
 238     }
 239 
 240     static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
 241         .orElseThrow(() ->
 242             new RuntimeException("jlink tool not found")
 243         );
 244 
 245     static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
 246         .orElseThrow(() ->
 247             new RuntimeException("jmod tool not found")
 248         );
 249 
 250     static final String MODULE_PATH = Paths.get(JAVA_HOME, "jmods").toString()
 251         + File.pathSeparator + MODS_DIR.toString();
 252 
 253     private void createImage(Path outputDir, String... modules) throws Throwable {
 254         assertTrue(JLINK_TOOL.run(System.out, System.out,
 255             "--output", outputDir.toString(),
 256             "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
 257             "--module-path", MODULE_PATH) == 0);
 258     }
 259 
 260     private static int jmod(String... options) {
 261         System.out.println("jmod " + Arrays.asList(options));
 262         return JMOD_TOOL.run(System.out, System.out, options);
 263     }
 264 }