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-jmod-section=headers:modules=java.base", 107 "--exclude-jmod-section=man:modules=java.base" 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-jmod-section=man:modules=java.base" 128 }, 129 List.of("man/tool2.1", 130 "man/tool3.1") }, 131 132 { new String [] { 133 "test4", 134 "--no-man-pages", 135 "--exclude-jmod-section=headers:modules=java.base,m2", 136 }, 137 List.of("include/m1a.h", 138 "include/m1b.h") 139 }, 140 141 { new String [] { 142 "test5", 143 "--exclude-jmod-section=man:modules=java.base,m1,m2", 144 "--no-header-files", 145 }, 146 List.of("man/tool3.1") 147 }, 148 }; 149 } 150 151 @Test(dataProvider = "jlinkoptions") 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 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 210 private Path createImage(String outputDir, List<String> options, 211 List<String> expectedFiles) { 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 252 final String name; 253 final Set<String> manPages = new HashSet<>(); 254 final Set<String> headerFiles = new HashSet<>(); 255 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 265 JmodFileBuilder manPage(String filename) { 266 manPages.add(filename); 267 return this; 268 } 269 270 JmodFileBuilder headerFile(String filename) { 271 headerFiles.add(filename); 272 return this; 273 } 274 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 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 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 }