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 /* 25 * @test 26 * @summary Test --no-man-pages and --no-header-files 27 * @library /test/lib 28 * @modules jdk.compiler 29 * jdk.jlink 30 * @build jdk.test.lib.compiler.CompilerUtils 31 * @run testng ExcludeJmodSectionPluginTest 32 */ 33 34 import java.io.BufferedWriter; 35 import java.io.File; 36 import java.io.IOException; 37 import java.io.PrintWriter; 38 import java.nio.file.FileVisitResult; 39 import java.nio.file.Files; 40 import java.nio.file.Path; 41 import java.nio.file.Paths; 42 import java.nio.file.SimpleFileVisitor; 43 import java.nio.file.attribute.BasicFileAttributes; 44 import java.util.ArrayList; 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Set; 48 import java.util.spi.ToolProvider; 49 import java.util.stream.Collectors; 50 import java.util.stream.Stream; 51 import jdk.test.lib.compiler.CompilerUtils; 52 53 import org.testng.annotations.BeforeTest; 54 import org.testng.annotations.DataProvider; 55 import org.testng.annotations.Test; 56 57 import static org.testng.Assert.*; 58 59 public class ExcludeJmodSectionPluginTest { 60 static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") 61 .orElseThrow(() -> 62 new RuntimeException("jmod tool not found") 63 ); 64 65 static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") 66 .orElseThrow(() -> 67 new RuntimeException("jlink tool not found") 68 ); 69 70 static final Path MODULE_PATH = Paths.get(System.getProperty("java.home"), "jmods"); 71 static final Path SRC_DIR = Paths.get("src"); 72 static final Path MODS_DIR = Paths.get("mods"); 73 static final Path JMODS_DIR = Paths.get("jmods"); 74 static final Path MAN_DIR = Paths.get("man"); 75 static final Path INCLUDE_DIR = Paths.get("include"); 76 static final Path IMAGES_DIR = Paths.get("images"); 77 78 @BeforeTest setup()79 private void setup() throws Exception { 80 // build jmod files 81 JmodFileBuilder m1 = new JmodFileBuilder("m1"); 82 m1.headerFile("m1a.h"); 83 m1.headerFile("m1b.h"); 84 m1.build(); 85 86 JmodFileBuilder m2 = new JmodFileBuilder("m2"); 87 m2.headerFile("m2.h"); 88 m2.manPage("tool2.1"); 89 m2.build(); 90 91 JmodFileBuilder m3 = new JmodFileBuilder("m3"); 92 m3.manPage("tool3.1"); 93 m3.build(); 94 } 95 imageDir(String dir)96 private String imageDir(String dir) { 97 return IMAGES_DIR.resolve(dir).toString(); 98 } 99 100 101 @DataProvider(name = "jlinkoptions") jlinkoptions()102 public Object[][] jlinkoptions() { 103 // options and expected header files & man pages 104 return new Object[][] { 105 { new String [] { 106 "test1", 107 "--exclude-files=/java.base/include/**,/java.base/man/**", 108 }, 109 List.of("include/m1a.h", 110 "include/m1b.h", 111 "include/m2.h", 112 "man/tool2.1", 113 "man/tool3.1") 114 }, 115 116 { new String [] { 117 "test2", 118 "--no-man-pages", 119 "--no-header-files", 120 }, 121 List.of() 122 }, 123 124 { new String[] { 125 "test3", 126 "--no-header-files", 127 "--exclude-files=/java.base/man/**" 128 }, 129 List.of("man/tool2.1", 130 "man/tool3.1") }, 131 132 { new String [] { 133 "test4", 134 "--no-man-pages", 135 "--exclude-files=/java.base/include/**,/m2/include/**", 136 }, 137 List.of("include/m1a.h", 138 "include/m1b.h") 139 }, 140 141 { new String [] { 142 "test5", 143 "--no-header-files", 144 "--exclude-files=/java.base/man/**,/m2/man/**" 145 }, 146 List.of("man/tool3.1") 147 }, 148 }; 149 } 150 151 @Test(dataProvider = "jlinkoptions") test(String[] opts, List<String> expectedFiles)152 public void test(String[] opts, List<String> expectedFiles) throws Exception { 153 if (Files.notExists(MODULE_PATH)) { 154 // exploded image 155 return; 156 } 157 158 String dir = opts[0]; 159 List<String> options = new ArrayList<>(); 160 for (int i = 1; i < opts.length; i++) { 161 options.add(opts[i]); 162 } 163 164 String mpath = MODULE_PATH.toString() + File.pathSeparator + 165 JMODS_DIR.toString(); 166 Stream.of("--module-path", mpath, 167 "--add-modules", "m1,m2,m3", 168 "--output", imageDir(dir)) 169 .forEach(options::add); 170 171 Path image = createImage(dir, options, expectedFiles); 172 173 // check if any unexpected header file or man page 174 Set<Path> extraFiles = Files.walk(image, Integer.MAX_VALUE) 175 .filter(p -> Files.isRegularFile(p)) 176 .filter(p -> p.getParent().endsWith("include") || 177 p.getParent().endsWith("man")) 178 .filter(p -> { 179 String fn = String.format("%s/%s", 180 p.getParent().getFileName().toString(), 181 p.getFileName().toString()); 182 return !expectedFiles.contains(fn); 183 }) 184 .collect(Collectors.toSet()); 185 186 if (extraFiles.size() > 0) { 187 System.out.println("Unexpected files: " + extraFiles.toString()); 188 assertTrue(extraFiles.isEmpty()); 189 } 190 } 191 192 /** 193 * Test java.base's include header files 194 */ 195 @Test testJavaBase()196 public void testJavaBase() { 197 if (Files.notExists(MODULE_PATH)) { 198 // exploded image 199 return; 200 } 201 List<String> options = List.of("--module-path", 202 MODULE_PATH.toString(), 203 "--add-modules", "java.base", 204 "--output", imageDir("base")); 205 createImage("base", options, 206 List.of("include/jni.h", "include/jvmti.h")); 207 208 } 209 createImage(String outputDir, List<String> options, List<String> expectedFiles)210 private Path createImage(String outputDir, List<String> options, 211 List<String> expectedFiles) { 212 System.out.println("jlink " + options.toString()); 213 int rc = JLINK_TOOL.run(System.out, System.out, 214 options.toArray(new String[0])); 215 assertTrue(rc == 0); 216 217 Path d = IMAGES_DIR.resolve(outputDir); 218 for (String fn : expectedFiles) { 219 Path path = d.resolve(fn); 220 if (Files.notExists(path)) { 221 throw new RuntimeException(path + " not found"); 222 } 223 } 224 return d; 225 } 226 deleteDirectory(Path dir)227 private void deleteDirectory(Path dir) throws IOException { 228 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 229 @Override 230 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 231 throws IOException 232 { 233 Files.delete(file); 234 return FileVisitResult.CONTINUE; 235 } 236 237 @Override 238 public FileVisitResult postVisitDirectory(Path dir, IOException exc) 239 throws IOException 240 { 241 Files.delete(dir); 242 return FileVisitResult.CONTINUE; 243 } 244 }); 245 } 246 247 /** 248 * Builder to create JMOD file 249 */ 250 class JmodFileBuilder { 251 252 final String name; 253 final Set<String> manPages = new HashSet<>(); 254 final Set<String> headerFiles = new HashSet<>(); 255 JmodFileBuilder(String name)256 JmodFileBuilder(String name) throws IOException { 257 this.name = name; 258 259 Path msrc = SRC_DIR.resolve(name); 260 if (Files.exists(msrc)) { 261 deleteDirectory(msrc); 262 } 263 } 264 manPage(String filename)265 JmodFileBuilder manPage(String filename) { 266 manPages.add(filename); 267 return this; 268 } 269 headerFile(String filename)270 JmodFileBuilder headerFile(String filename) { 271 headerFiles.add(filename); 272 return this; 273 } 274 build()275 Path build() throws IOException { 276 compileModule(); 277 // create man pages 278 Path mdir = MAN_DIR.resolve(name); 279 for (String filename : manPages) { 280 Files.createDirectories(mdir); 281 Files.createFile(mdir.resolve(filename)); 282 } 283 // create header files 284 mdir = INCLUDE_DIR.resolve(name); 285 for (String filename : headerFiles) { 286 Files.createDirectories(mdir); 287 Files.createFile(mdir.resolve(filename)); 288 } 289 return createJmodFile(); 290 } 291 compileModule()292 void compileModule() throws IOException { 293 Path msrc = SRC_DIR.resolve(name); 294 Files.createDirectories(msrc); 295 Path minfo = msrc.resolve("module-info.java"); 296 try (BufferedWriter bw = Files.newBufferedWriter(minfo); 297 PrintWriter writer = new PrintWriter(bw)) { 298 writer.format("module %s { }%n", name); 299 } 300 301 assertTrue(CompilerUtils.compile(msrc, MODS_DIR, 302 "--module-source-path", 303 SRC_DIR.toString())); 304 } 305 createJmodFile()306 Path createJmodFile() throws IOException { 307 Path mclasses = MODS_DIR.resolve(name); 308 Files.createDirectories(JMODS_DIR); 309 Path outfile = JMODS_DIR.resolve(name + ".jmod"); 310 List<String> args = new ArrayList<>(); 311 args.add("create"); 312 // add classes 313 args.add("--class-path"); 314 args.add(mclasses.toString()); 315 // man pages 316 if (manPages.size() > 0) { 317 args.add("--man-pages"); 318 args.add(MAN_DIR.resolve(name).toString()); 319 } 320 // header files 321 if (headerFiles.size() > 0) { 322 args.add("--header-files"); 323 args.add(INCLUDE_DIR.resolve(name).toString()); 324 } 325 args.add(outfile.toString()); 326 327 if (Files.exists(outfile)) 328 Files.delete(outfile); 329 330 System.out.println("jmod " + 331 args.stream().collect(Collectors.joining(" "))); 332 333 int rc = JMOD_TOOL.run(System.out, System.out, 334 args.toArray(new String[args.size()])); 335 if (rc != 0) { 336 throw new AssertionError("jmod failed: rc = " + rc); 337 } 338 return outfile; 339 } 340 } 341 } 342