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", "m5"};
  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     @Test
 164     public void testRequiresStatic() throws Throwable {
 165         if (!hasJmods()) return;
 166 
 167         Path dir = Paths.get("requiresStatic");
 168         createImage(dir, "m5");
 169         Path java = dir.resolve("bin").resolve("java");
 170         assertTrue(executeProcess(java.toString(), "-m", "m5/p5.Main")
 171                         .outputTo(System.out)
 172                         .errorTo(System.out)
 173                         .getExitValue() == 0);
 174 
 175         // run with m3 present
 176         assertTrue(executeProcess(java.toString(),
 177                                   "--module-path", MODS_DIR.toString(),
 178                                   "--add-modules", "m3",
 179                                   "-m", "m5/p5.Main")
 180                         .outputTo(System.out)
 181                         .errorTo(System.out)
 182                         .getExitValue() == 0);
 183     }
 184 
 185     @Test
 186     public void testRequiresStatic2() throws Throwable {
 187         if (!hasJmods()) return;
 188 
 189         Path dir = Paths.get("requiresStatic2");
 190         createImage(dir, "m3", "m5");
 191 
 192         Path java = dir.resolve("bin").resolve("java");
 193         assertTrue(executeProcess(java.toString(), "-m", "m5/p5.Main")
 194                         .outputTo(System.out)
 195                         .errorTo(System.out)
 196                         .getExitValue() == 0);
 197 
 198         // boot layer with m3 and m5
 199         assertTrue(executeProcess(java.toString(),
 200                                   "--add-modules", "m3",
 201                                   "-m", "m5/p5.Main")
 202                         .outputTo(System.out)
 203                         .errorTo(System.out)
 204                         .getExitValue() == 0);
 205     }
 206 
 207     private void createJmods(String... modules) throws IOException {
 208         // use the same target platform as in java.base
 209         ModuleDescriptor md = Layer.boot().findModule("java.base").get()
 210                                    .getDescriptor();
 211         String osName = md.osName().get();
 212         String osArch = md.osArch().get();
 213 
 214         // create JMOD files
 215         Files.createDirectories(JMODS_DIR);
 216         Stream.of(modules).forEach(mn ->
 217             assertTrue(jmod("create",
 218                 "--class-path", MODS_DIR.resolve(mn).toString(),
 219                 "--os-name", osName,
 220                 "--os-arch", osArch,
 221                 "--main-class", mn.replace('m', 'p') + ".Main",
 222                 JMODS_DIR.resolve(mn + ".jmod").toString()) == 0)
 223         );
 224     }
 225 
 226 
 227     /**
 228      * Verify the module descriptor if package p4.dummy is excluded at link time.
 229      */
 230     @Test
 231     public void testModulePackagesAttribute() throws Throwable {
 232         if (!hasJmods()) return;
 233 
 234         // create an image using JMOD files
 235         Path dir = Paths.get("packagesTest");
 236         String mp = Paths.get(JAVA_HOME, "jmods").toString() +
 237             File.pathSeparator + JMODS_DIR.toString();
 238 
 239         Set<String> modules = Set.of("m1", "m4");
 240         assertTrue(JLINK_TOOL.run(System.out, System.out,
 241             "--output", dir.toString(),
 242             "--exclude-resources", "m4/p4/dummy/*",
 243             "--add-modules", modules.stream().collect(Collectors.joining(",")),
 244             "--module-path", mp) == 0);
 245 
 246         // verify ModuleDescriptor
 247         Path java = dir.resolve("bin").resolve("java");
 248         assertTrue(executeProcess(java.toString(),
 249                         "--add-modules=m1", "-m", "m4")
 250             .outputTo(System.out)
 251             .errorTo(System.out)
 252             .getExitValue() == 0);
 253     }
 254 
 255     /**
 256      * Verify the plugin to retain ModuleTarget attribute
 257      */
 258     @Test
 259     public void testRetainModuleTarget() throws Throwable {
 260         if (!hasJmods()) return;
 261 
 262         // create an image using JMOD files
 263         Path dir = Paths.get("retainModuleTargetTest");
 264         String mp = Paths.get(JAVA_HOME, "jmods").toString() +
 265             File.pathSeparator + JMODS_DIR.toString();
 266 
 267         Set<String> modules = Set.of("m1", "m4");
 268         assertTrue(JLINK_TOOL.run(System.out, System.out,
 269             "--output", dir.toString(),
 270             "--system-modules", "retainModuleTarget",
 271             "--exclude-resources", "m4/p4/dummy/*",
 272             "--add-modules", modules.stream().collect(Collectors.joining(",")),
 273             "--module-path", mp) == 0);
 274 
 275         // verify ModuleDescriptor
 276         Path java = dir.resolve("bin").resolve("java");
 277         assertTrue(executeProcess(java.toString(),
 278                         "--add-modules=m1", "-m", "m4", "retainModuleTarget")
 279             .outputTo(System.out)
 280             .errorTo(System.out)
 281             .getExitValue() == 0);
 282     }
 283 
 284     static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
 285         .orElseThrow(() ->
 286             new RuntimeException("jlink tool not found")
 287         );
 288 
 289     static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
 290         .orElseThrow(() ->
 291             new RuntimeException("jmod tool not found")
 292         );
 293 
 294     static final String MODULE_PATH = Paths.get(JAVA_HOME, "jmods").toString()
 295         + File.pathSeparator + MODS_DIR.toString();
 296 
 297     private void createImage(Path outputDir, String... modules) throws Throwable {
 298         assertTrue(JLINK_TOOL.run(System.out, System.out,
 299             "--output", outputDir.toString(),
 300             "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
 301             "--module-path", MODULE_PATH) == 0);
 302     }
 303 
 304     private static int jmod(String... options) {
 305         System.out.println("jmod " + Arrays.asList(options));
 306         return JMOD_TOOL.run(System.out, System.out, options);
 307     }
 308 }