1 /*
   2  * Copyright (c) 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.PrintWriter;
  26 import java.io.StringWriter;
  27 import java.nio.file.Files;
  28 import java.nio.file.Path;
  29 import java.nio.file.Paths;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import java.util.spi.ToolProvider;
  33 import java.util.stream.Collectors;
  34 import java.util.stream.Stream;
  35 
  36 import static jdk.testlibrary.Asserts.assertTrue;
  37 import static jdk.testlibrary.ProcessTools.*;
  38 
  39 import org.testng.annotations.BeforeTest;
  40 import org.testng.annotations.Test;
  41 import static org.testng.Assert.*;
  42 
  43 /**
  44  * @test
  45  * @bug 8174826
  46  * @library /lib/testlibrary
  47  * @modules jdk.compiler jdk.jlink
  48  * @build BindServices CompilerUtils jdk.testlibrary.ProcessTools
  49  * @run testng BindServices
  50  */
  51 
  52 public class BindServices {
  53     private static final String JAVA_HOME = System.getProperty("java.home");
  54     private static final String TEST_SRC = System.getProperty("test.src");
  55 
  56     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  57     private static final Path MODS_DIR = Paths.get("mods");
  58 
  59     private static final String MODULE_PATH =
  60         Paths.get(JAVA_HOME, "jmods").toString() +
  61             File.pathSeparator + MODS_DIR.toString();
  62 
  63     // the names of the modules in this test
  64     private static String[] modules = new String[] {"m1", "m2", "m3"};
  65 
  66 
  67     private static boolean hasJmods() {
  68         if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
  69             System.err.println("Test skipped. NO jmods directory");
  70             return false;
  71         }
  72         return true;
  73     }
  74 
  75     /*
  76      * Compiles all modules used by the test
  77      */
  78     @BeforeTest
  79     public void compileAll() throws Throwable {
  80         if (!hasJmods()) return;
  81 
  82         for (String mn : modules) {
  83             Path msrc = SRC_DIR.resolve(mn);
  84             assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
  85                 "--module-source-path", SRC_DIR.toString()));
  86         }
  87     }
  88 
  89     @Test
  90     public void noServiceBinding() throws Throwable {
  91         if (!hasJmods()) return;
  92 
  93         Path dir = Paths.get("noServiceBinding");
  94 
  95         // no service binding and does not link m2,m3 providers.
  96         JLink.run("--output", dir.toString(),
  97                   "--module-path", MODULE_PATH,
  98                   "--add-modules", "m1").output();
  99 
 100         testImage(dir, "m1");
 101     }
 102 
 103     @Test
 104     public void fullServiceBinding() throws Throwable {
 105         if (!hasJmods()) return;
 106 
 107         Path dir = Paths.get("fullServiceBinding");
 108 
 109         // full service binding
 110         // m2 is a provider used by m1.  During service binding, when m2 is
 111         // resolved, m2 uses p2.T that causes m3 to be linked as it is a
 112         // provider to p2.T
 113         JLink.run("--output", dir.toString(),
 114                   "--module-path", MODULE_PATH,
 115                   "--add-modules", "m1",
 116                   "--bind-services",
 117                   "--limit-modules", "m1,m2,m3,java.base");
 118 
 119         testImage(dir, "m1", "m2", "m3");
 120     }
 121 
 122     @Test
 123     public void testVerbose() throws Throwable {
 124         if (!hasJmods()) return;
 125 
 126         Path dir = Paths.get("verbose");
 127 
 128         List<String> output =
 129             JLink.run("--output", dir.toString(),
 130                       "--module-path", MODULE_PATH,
 131                       "--add-modules", "m1",
 132                       "--bind-services",
 133                       "--verbose",
 134                       "--limit-modules", "m1,m2,m3,java.base").output();
 135 
 136         List<String> expected = List.of(
 137             "module m1 (" + MODS_DIR.resolve("m1").toUri().toString() + ")",
 138             "module m2 (" + MODS_DIR.resolve("m2").toUri().toString() + ")",
 139             "module m3 (" + MODS_DIR.resolve("m3").toUri().toString() + ")",
 140             "module m1 provides p1.S, used by m1",
 141             "module m2 provides p1.S, used by m1",
 142             "module m2 provides p2.T, used by m2",
 143             "module m3 provides p2.T, used by m2"
 144         );
 145 
 146         assertTrue(output.containsAll(expected));
 147 
 148         testImage(dir, "m1", "m2", "m3");
 149     }
 150 
 151     /*
 152      * Tests the given ${java.home} to only contain the specified modules
 153      */
 154     private void testImage(Path javaHome, String... modules) throws Throwable {
 155         Path java = javaHome.resolve("bin").resolve("java");
 156         String[] cmd = Stream.concat(
 157             Stream.of(java.toString(), "-m", "m1/p1.Main"),
 158             Stream.of(modules)).toArray(String[]::new);
 159 
 160         assertTrue(executeProcess(cmd).outputTo(System.out)
 161                                       .errorTo(System.out)
 162                                       .getExitValue() == 0);
 163     }
 164 
 165     static class JLink {
 166         static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
 167             .orElseThrow(() ->
 168                 new RuntimeException("jlink tool not found")
 169             );
 170 
 171         static JLink run(String... options) {
 172             JLink jlink = new JLink();
 173             assertTrue(jlink.execute(options) == 0);
 174             return jlink;
 175         }
 176 
 177         final List<String> output = new ArrayList<>();
 178         private int execute(String... options) {
 179             System.out.println("jlink " +
 180                 Stream.of(options).collect(Collectors.joining(" ")));
 181 
 182             StringWriter writer = new StringWriter();
 183             PrintWriter pw = new PrintWriter(writer);
 184             int rc = JLINK_TOOL.run(pw, pw, options);
 185             System.out.println(writer.toString());
 186             Stream.of(writer.toString().split("\\v"))
 187                   .map(String::trim)
 188                   .forEach(output::add);
 189             return rc;
 190         }
 191 
 192         boolean contains(String s) {
 193             return output.contains(s);
 194         }
 195 
 196         List<String> output() {
 197             return output;
 198         }
 199     }
 200 }