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 org.testng.annotations.BeforeTest; 37 import org.testng.annotations.Test; 38 import static org.testng.Assert.*; 39 40 /** 41 * @test 42 * @bug 8174826 43 * @library /lib/testlibrary 44 * @modules jdk.charsets jdk.compiler jdk.jlink 45 * @build SuggestProviders CompilerUtils 46 * @run testng SuggestProviders 47 */ 48 49 public class SuggestProviders { 50 private static final String JAVA_HOME = System.getProperty("java.home"); 51 private static final String TEST_SRC = System.getProperty("test.src"); 52 53 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 54 private static final Path MODS_DIR = Paths.get("mods"); 55 56 private static final String MODULE_PATH = 57 Paths.get(JAVA_HOME, "jmods").toString() + 58 File.pathSeparator + MODS_DIR.toString(); 59 60 // the names of the modules in this test 61 private static String[] modules = new String[] {"m1", "m2", "m3"}; 62 63 64 private static boolean hasJmods() { 65 if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) { 66 System.err.println("Test skipped. NO jmods directory"); 67 return false; 68 } 69 return true; 70 } 71 72 /* 73 * Compiles all modules used by the test 74 */ 75 @BeforeTest 76 public void compileAll() throws Throwable { 77 if (!hasJmods()) return; 78 79 for (String mn : modules) { 80 Path msrc = SRC_DIR.resolve(mn); 81 assertTrue(CompilerUtils.compile(msrc, MODS_DIR, 82 "--module-source-path", SRC_DIR.toString())); 83 } 84 } 85 86 // check a subset of services used by java.base 87 private final List<String> JAVA_BASE_USES = List.of( 88 "uses java.lang.System$LoggerFinder", 89 "uses java.net.ContentHandlerFactory", 90 "uses java.net.spi.URLStreamHandlerProvider", 91 "uses java.nio.channels.spi.AsynchronousChannelProvider", 92 "uses java.nio.channels.spi.SelectorProvider", 93 "uses java.nio.charset.spi.CharsetProvider", 94 "uses java.nio.file.spi.FileSystemProvider", 95 "uses java.nio.file.spi.FileTypeDetector", 96 "uses java.security.Provider", 97 "uses java.util.spi.ToolProvider" 98 ); 99 100 private final List<String> JAVA_BASE_PROVIDERS = List.of( 101 "java.base provides java.nio.file.spi.FileSystemProvider used by java.base" 102 ); 103 104 private final List<String> SYSTEM_PROVIDERS = List.of( 105 "jdk.charsets provides java.nio.charset.spi.CharsetProvider used by java.base", 106 "jdk.compiler provides java.util.spi.ToolProvider used by java.base", 107 "jdk.compiler provides javax.tools.JavaCompiler used by java.compiler", 108 "jdk.jlink provides jdk.tools.jlink.plugin.Plugin used by jdk.jlink", 109 "jdk.jlink provides java.util.spi.ToolProvider used by java.base" 110 ); 111 112 private final List<String> APP_USES = List.of( 113 "uses p1.S", 114 "uses p2.T" 115 ); 116 117 private final List<String> APP_PROVIDERS = List.of( 118 "m1 provides p1.S used by m1", 119 "m2 provides p1.S used by m1", 120 "m2 provides p2.T used by m2", 121 "m3 provides p2.T used by m2", 122 "m3 provides p3.S not used by any observable module" 123 ); 124 125 @Test 126 public void suggestProviders() throws Throwable { 127 if (!hasJmods()) return; 128 129 List<String> output = JLink.run("--module-path", MODULE_PATH, 130 "--suggest-providers").output(); 131 132 Stream<String> uses = 133 Stream.concat(JAVA_BASE_USES.stream(), APP_USES.stream()); 134 Stream<String> providers = 135 Stream.concat(SYSTEM_PROVIDERS.stream(), APP_PROVIDERS.stream()); 136 137 assertTrue(output.containsAll(Stream.concat(uses, providers) 138 .collect(Collectors.toList()))); 139 } 140 141 /** 142 * find providers from the observable modules and --add-modules has no 143 * effect on the suggested providers 144 */ 145 @Test 146 public void observableModules() throws Throwable { 147 if (!hasJmods()) return; 148 149 List<String> output = JLink.run("--module-path", MODULE_PATH, 150 "--add-modules", "m1", 151 "--suggest-providers").output(); 152 153 Stream<String> uses = 154 Stream.concat(JAVA_BASE_USES.stream(), Stream.of("uses p1.S")); 155 Stream<String> providers = 156 Stream.concat(SYSTEM_PROVIDERS.stream(), APP_PROVIDERS.stream()); 157 158 assertTrue(output.containsAll(Stream.concat(uses, providers) 159 .collect(Collectors.toList()))); 160 } 161 162 /** 163 * find providers from the observable modules with --limit-modules 164 */ 165 @Test 166 public void limitModules() throws Throwable { 167 if (!hasJmods()) return; 168 169 List<String> output = JLink.run("--module-path", MODULE_PATH, 170 "--limit-modules", "m1", 171 "--suggest-providers").output(); 172 173 Stream<String> uses = 174 Stream.concat(JAVA_BASE_USES.stream(), Stream.of("uses p1.S")); 175 Stream<String> providers = 176 Stream.concat(JAVA_BASE_PROVIDERS.stream(), 177 Stream.of("m1 provides p1.S used by m1") 178 ); 179 180 assertTrue(output.containsAll(Stream.concat(uses, providers) 181 .collect(Collectors.toList()))); 182 } 183 184 @Test 185 public void providersForServices() throws Throwable { 186 if (!hasJmods()) return; 187 188 List<String> output = 189 JLink.run("--module-path", MODULE_PATH, 190 "--suggest-providers", 191 "java.nio.charset.spi.CharsetProvider,p1.S").output(); 192 193 System.out.println(output); 194 Stream<String> expected = Stream.concat( 195 Stream.of("jdk.charsets provides java.nio.charset.spi.CharsetProvider used by java.base"), 196 Stream.of("m1 provides p1.S used by m1", 197 "m2 provides p1.S used by m1") 198 ); 199 200 assertTrue(output.containsAll(expected.collect(Collectors.toList()))); 201 } 202 203 @Test 204 public void unusedService() throws Throwable { 205 if (!hasJmods()) return; 206 207 List<String> output = 208 JLink.run("--module-path", MODULE_PATH, 209 "--suggest-providers", 210 "p3.S").output(); 211 212 List<String> expected = List.of( 213 "m3 provides p3.S not used by any observable module" 214 ); 215 assertTrue(output.containsAll(expected)); 216 217 // should not print other services m3 provides 218 assertFalse(output.contains("m3 provides p2.T used by m2")); 219 } 220 221 @Test 222 public void nonExistentService() throws Throwable { 223 if (!hasJmods()) return; 224 225 List<String> output = 226 JLink.run("--module-path", MODULE_PATH, 227 "--suggest-providers", 228 "nonExistentType").output(); 229 230 List<String> expected = List.of( 231 "No provider found for service specified to --suggest-providers: nonExistentType" 232 ); 233 assertTrue(output.containsAll(expected)); 234 } 235 236 @Test 237 public void noSuggestProviders() throws Throwable { 238 if (!hasJmods()) return; 239 240 List<String> output = 241 JLink.run("--module-path", MODULE_PATH, 242 "--bind-services", 243 "--suggest-providers").output(); 244 245 String expected = "--bind-services option is specified. No additional providers suggested."; 246 assertTrue(output.contains(expected)); 247 248 } 249 250 @Test 251 public void suggestTypeNotRealProvider() throws Throwable { 252 if (!hasJmods()) return; 253 254 List<String> output = 255 JLink.run("--module-path", MODULE_PATH, 256 "--add-modules", "m1", 257 "--suggest-providers", 258 "java.util.List").output(); 259 260 System.out.println(output); 261 List<String> expected = List.of( 262 "No provider found for service specified to --suggest-providers: java.util.List" 263 ); 264 265 assertTrue(output.containsAll(expected)); 266 } 267 268 @Test 269 public void addNonObservableModule() throws Throwable { 270 if (!hasJmods()) return; 271 272 List<String> output = 273 JLink.run("--module-path", MODULE_PATH, 274 "--add-modules", "nonExistentModule", 275 "--suggest-providers", 276 "java.nio.charset.spi.CharsetProvider").output(); 277 278 System.out.println(output); 279 List<String> expected = List.of( 280 "jdk.charsets provides java.nio.charset.spi.CharsetProvider used by java.base" 281 ); 282 283 assertTrue(output.containsAll(expected)); 284 } 285 286 static class JLink { 287 static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") 288 .orElseThrow(() -> 289 new RuntimeException("jlink tool not found") 290 ); 291 292 static JLink run(String... options) { 293 JLink jlink = new JLink(); 294 assertTrue(jlink.execute(options) == 0); 295 return jlink; 296 } 297 298 final List<String> output = new ArrayList<>(); 299 private int execute(String... options) { 300 System.out.println("jlink " + 301 Stream.of(options).collect(Collectors.joining(" "))); 302 303 StringWriter writer = new StringWriter(); 304 PrintWriter pw = new PrintWriter(writer); 305 int rc = JLINK_TOOL.run(pw, pw, options); 306 System.out.println(writer.toString()); 307 Stream.of(writer.toString().split("\\v")) 308 .map(String::trim) 309 .forEach(output::add); 310 return rc; 311 } 312 313 boolean contains(String s) { 314 return output.contains(s); 315 } 316 317 List<String> output() { 318 return output; 319 } 320 } 321 }