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