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