1 /** 2 * Copyright (c) 2015, 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 * @modules jdk.jlink/jdk.tools.jmod 27 * @library /lib/testlibrary /jdk/jigsaw/lib 28 * @modules jdk.compiler 29 * @build jdk.testlibrary.FileUtils CompilerUtils 30 * @run testng JmodNegativeTest 31 * @summary Negative tests for jmod 32 */ 33 34 import java.io.*; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.nio.file.Paths; 38 import java.util.Arrays; 39 import java.util.List; 40 import java.util.function.Consumer; 41 import java.util.function.Supplier; 42 import java.util.zip.ZipOutputStream; 43 import jdk.testlibrary.FileUtils; 44 import org.testng.annotations.BeforeTest; 45 import org.testng.annotations.DataProvider; 46 import org.testng.annotations.Test; 47 48 import static java.io.File.pathSeparator; 49 import static java.nio.charset.StandardCharsets.UTF_8; 50 import static org.testng.Assert.assertTrue; 51 52 public class JmodNegativeTest { 53 54 static final String TEST_SRC = System.getProperty("test.src", "."); 55 static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 56 static final Path EXPLODED_DIR = Paths.get("build"); 57 static final Path MODS_DIR = Paths.get("jmods"); 58 59 @BeforeTest 60 public void buildExplodedModules() throws IOException { 61 if (Files.exists(EXPLODED_DIR)) 62 FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); 63 64 for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { 65 Path dir = EXPLODED_DIR.resolve(name); 66 assertTrue(compileModule(name, dir.resolve("classes"))); 67 } 68 69 if (Files.exists(MODS_DIR)) 70 FileUtils.deleteFileTreeWithRetry(MODS_DIR); 71 Files.createDirectories(MODS_DIR); 72 } 73 74 @Test 75 public void testNoArgs() { 76 jmod("") 77 .assertFailure() 78 .resultChecker(r -> 79 assertContains(r.output, "Error: One of options -ctp must be specified.") 80 ); 81 } 82 83 @Test 84 public void testBadAction() { 85 jmod("badAction") 86 .assertFailure() 87 .resultChecker(r -> 88 assertContains(r.output, "Error: One of options -ctp must be specified.") 89 ); 90 91 jmod("--badOption") 92 .assertFailure() 93 .resultChecker(r -> 94 assertContains(r.output, "Error: 'badOption' is not a recognized option") 95 ); 96 } 97 98 @Test 99 public void testTooManyArgs() throws IOException { 100 Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); 101 FileUtils.deleteFileIfExistsWithRetry(jmod); 102 103 jmod("--create", 104 jmod.toString(), 105 "AAA") 106 .assertFailure() 107 .resultChecker(r -> 108 assertContains(r.output, "Error: unknown option(s): [AAA]") 109 ); 110 } 111 112 @Test 113 public void testCreateNoArgs() { 114 jmod("--create") 115 .assertFailure() 116 .resultChecker(r -> 117 assertContains(r.output, "Error: jmod-file must be specified") 118 ); 119 } 120 121 @Test 122 public void testListNoArgs() { 123 jmod("--list") 124 .assertFailure() 125 .resultChecker(r -> 126 assertContains(r.output, "Error: jmod-file must be specified") 127 ); 128 } 129 130 @Test 131 public void testListFileDoesNotExist() throws IOException { 132 Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); 133 FileUtils.deleteFileIfExistsWithRetry(jmod); 134 135 jmod("--list", 136 jmod.toString()) 137 .assertFailure() 138 .resultChecker(r -> 139 assertContains(r.output, "Error: no jmod file found: " 140 + jmod.toString()) 141 ); 142 } 143 144 @Test 145 public void testListJmodIsDir() throws IOException { 146 Path jmod = MODS_DIR.resolve("testListJmodIsDir.jmod"); 147 if (Files.notExists(jmod)) 148 Files.createDirectory(jmod); 149 150 jmod("--list", 151 jmod.toString()) 152 .assertFailure() 153 .resultChecker(r -> 154 assertContains(r.output, "Error: error opening jmod file") 155 ); 156 } 157 158 @Test 159 public void testlistJmodMalformed() throws IOException { 160 Path jmod = MODS_DIR.resolve("testlistJmodMalformed.jmod"); 161 if (Files.notExists(jmod)) 162 Files.createFile(jmod); 163 164 jmod("--list", 165 jmod.toString()) 166 .assertFailure() 167 .resultChecker(r -> 168 assertContains(r.output, "Error: error opening jmod file") 169 ); 170 } 171 172 @Test 173 public void testHashDependenciesModulePathNotSpecified() { 174 jmod("--create", 175 "--hash-dependencies", "anyPattern.*", 176 "output.jmod") 177 .assertFailure() 178 .resultChecker(r -> 179 assertContains(r.output, "Error: --module-path must be " 180 +"specified when hashing dependencies") 181 ); 182 } 183 184 @Test 185 public void testCreateJmodAlreadyExists() throws IOException { 186 Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists.jmod"); 187 if (Files.notExists(jmod)) 188 Files.createFile(jmod); 189 190 jmod("--create", 191 "--class-path", Paths.get(".").toString(), // anything that exists 192 jmod.toString()) 193 .assertFailure() 194 .resultChecker(r -> 195 assertContains(r.output, "Error: file already exists: " + jmod.toString()) 196 ); 197 } 198 199 @Test 200 public void testCreateJmodIsDir() throws IOException { 201 Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists"); 202 if (Files.notExists(jmod)) 203 Files.createDirectory(jmod); 204 205 jmod("--create", 206 "--class-path", Paths.get(".").toString(), // anything that exists 207 jmod.toString()) 208 .assertFailure() 209 .resultChecker(r -> 210 assertContains(r.output, "Error: file already exists: " + jmod.toString()) 211 ); 212 } 213 214 @Test 215 public void testInvalidModuleVersion() throws IOException { 216 Path jmod = MODS_DIR.resolve("testEmptyModuleVersion.jmod"); 217 FileUtils.deleteFileIfExistsWithRetry(jmod); 218 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 219 220 for (String version : new String[] { "", "NOT_A_VALID_VERSION" }) { 221 jmod("--create", 222 "--class-path", cp, 223 "--module-version", version, 224 jmod.toString()) 225 .assertFailure() 226 .resultChecker(r -> 227 assertContains(r.output, "Error: invalid module version") 228 ); 229 } 230 } 231 232 @Test(enabled = false) // TODO: jmod should check for duplicates before creating. 233 public void testDuplicates() throws IOException { 234 Path jmod = MODS_DIR.resolve("testDuplicates.jmod"); 235 FileUtils.deleteFileIfExistsWithRetry(jmod); 236 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 237 238 jmod("--create", 239 "--class-path", cp + pathSeparator + cp, 240 jmod.toString()) 241 .assertFailure() 242 .resultChecker(r -> 243 assertContains(r.output, "Error: duplicate resource found, etc..") 244 ); 245 } 246 247 @Test 248 public void testEmptyFileInClasspath() throws IOException { 249 Path jmod = MODS_DIR.resolve("testEmptyFileInClasspath.jmod"); 250 FileUtils.deleteFileIfExistsWithRetry(jmod); 251 Path jar = MODS_DIR.resolve("NotARealJar_Empty.jar"); 252 FileUtils.deleteFileIfExistsWithRetry(jar); 253 Files.createFile(jar); 254 255 jmod("--create", 256 "--class-path", jar.toString(), 257 jmod.toString()) 258 .assertFailure() 259 .resultChecker(r -> 260 assertContains(r.output, "Error: module-info.class not found") 261 ); 262 } 263 264 @Test 265 public void testEmptyJarInClasspath() throws IOException { 266 Path jmod = MODS_DIR.resolve("testEmptyJarInClasspath.jmod"); 267 FileUtils.deleteFileIfExistsWithRetry(jmod); 268 Path jar = MODS_DIR.resolve("empty.jar"); 269 FileUtils.deleteFileIfExistsWithRetry(jar); 270 try (FileOutputStream fos = new FileOutputStream(jar.toFile()); 271 ZipOutputStream zos = new ZipOutputStream(fos)) { 272 // empty 273 } 274 275 jmod("--create", 276 "--class-path", jar.toString(), 277 jmod.toString()) 278 .assertFailure() 279 .resultChecker(r -> 280 assertContains(r.output, "Error: module-info.class not found") 281 ); 282 } 283 284 @Test 285 public void testModuleInfoNotFound() throws IOException { 286 Path jmod = MODS_DIR.resolve("output.jmod"); 287 FileUtils.deleteFileIfExistsWithRetry(jmod); 288 Path jar = MODS_DIR.resolve("empty"); 289 FileUtils.deleteFileIfExistsWithRetry(jar); 290 Files.createDirectory(jar); 291 292 jmod("--create", 293 "--class-path", jar.toString(), 294 jmod.toString()) 295 .assertFailure() 296 .resultChecker(r -> 297 assertContains(r.output, "Error: module-info.class not found") 298 ); 299 } 300 301 @Test 302 public void testModuleInfoIsDir() throws IOException { 303 Path jmod = MODS_DIR.resolve("output.jmod"); 304 FileUtils.deleteFileIfExistsWithRetry(jmod); 305 Path cp = MODS_DIR.resolve("module-info.class"); 306 FileUtils.deleteFileIfExistsWithRetry(cp); 307 Files.createDirectory(cp); 308 Files.createFile(cp.resolve("nada.txt")); 309 310 jmod("--create", 311 "--class-path", cp.toString(), 312 jmod.toString()) 313 .assertFailure() 314 .resultChecker(r -> 315 assertContains(r.output, "Error: module-info.class not found") 316 ); 317 } 318 319 @Test 320 public void testDependencyNotFound() throws IOException { 321 Path jmod = MODS_DIR.resolve("output.jmod"); 322 FileUtils.deleteFileIfExistsWithRetry(jmod); 323 Path emptyDir = Paths.get("empty"); 324 if (Files.exists(emptyDir)) 325 FileUtils.deleteFileTreeWithRetry(emptyDir); 326 Files.createDirectory(emptyDir); 327 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 328 329 jmod("--create", 330 "--class-path", cp, 331 "--hash-dependencies", ".*", 332 "--modulepath", emptyDir.toString(), 333 jmod.toString()) 334 .assertFailure() 335 .resultChecker(r -> 336 assertContains(r.output, "Hashing module foo dependencies, " 337 + "unable to find module java.base on module path") 338 ); 339 } 340 341 @Test 342 public void testEmptyFileInModulePath() throws IOException { 343 Path jmod = MODS_DIR.resolve("output.jmod"); 344 FileUtils.deleteFileIfExistsWithRetry(jmod); 345 Path empty = MODS_DIR.resolve("emptyFile.jmod"); 346 FileUtils.deleteFileIfExistsWithRetry(empty); 347 Files.createFile(empty); 348 try { 349 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 350 351 jmod("--create", 352 "--class-path", cp, 353 "--hash-dependencies", ".*", 354 "--modulepath", MODS_DIR.toString(), 355 jmod.toString()) 356 .assertFailure() 357 .resultChecker(r -> 358 assertContains(r.output, "Error: error reading module path") 359 ); 360 } finally { 361 FileUtils.deleteFileWithRetry(empty); 362 } 363 } 364 365 @Test 366 public void testFileInModulePath() throws IOException { 367 Path jmod = MODS_DIR.resolve("output.jmod"); 368 FileUtils.deleteFileIfExistsWithRetry(jmod); 369 Path file = MODS_DIR.resolve("testFileInModulePath.txt"); 370 FileUtils.deleteFileIfExistsWithRetry(file); 371 Files.createFile(file); 372 373 jmod("--create", 374 "--hash-dependencies", ".*", 375 "--modulepath", file.toString(), 376 jmod.toString()) 377 .assertFailure() 378 .resultChecker(r -> 379 assertContains(r.output, "Error: path must be a directory") 380 ); 381 } 382 383 @DataProvider(name = "pathDoesNotExist") 384 public Object[][] pathDoesNotExist() throws IOException { 385 Path jmod = MODS_DIR.resolve("output.jmod"); 386 FileUtils.deleteFileIfExistsWithRetry(jmod); 387 FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); 388 389 List<Supplier<JmodResult>> tasks = Arrays.asList( 390 () -> jmod("--create", 391 "--hash-dependencies", "anyPattern", 392 "--modulepath", "doesNotExist", 393 "output.jmod"), 394 () -> jmod("--create", 395 "--class-path", "doesNotExist", 396 "output.jmod"), 397 () -> jmod("--create", 398 "--class-path", "doesNotExist.jar", 399 "output.jmod"), 400 () -> jmod("--create", 401 "--cmds", "doesNotExist", 402 "output.jmod"), 403 () -> jmod("--create", 404 "--config", "doesNotExist", 405 "output.jmod"), 406 () -> jmod("--create", 407 "--libs", "doesNotExist", 408 "output.jmod") ); 409 410 String errMsg = "Error: path not found: doesNotExist"; 411 return tasks.stream().map(t -> new Object[] {t, errMsg} ) 412 .toArray(Object[][]::new); 413 } 414 415 @Test(dataProvider = "pathDoesNotExist") 416 public void testPathDoesNotExist(Supplier<JmodResult> supplier, 417 String errMsg) 418 { 419 supplier.get() 420 .assertFailure() 421 .resultChecker(r -> { 422 assertContains(r.output, errMsg); 423 }); 424 } 425 426 @DataProvider(name = "partOfPathDoesNotExist") 427 public Object[][] partOfPathDoesNotExist() throws IOException { 428 Path jmod = MODS_DIR.resolve("output.jmod"); 429 FileUtils.deleteFileIfExistsWithRetry(jmod); 430 FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); 431 432 Path emptyDir = Paths.get("empty"); 433 if (Files.exists(emptyDir)) 434 FileUtils.deleteFileTreeWithRetry(emptyDir); 435 Files.createDirectory(emptyDir); 436 437 List<Supplier<JmodResult>> tasks = Arrays.asList( 438 () -> jmod("--create", 439 "--hash-dependencies", "anyPattern", 440 "--modulepath","empty" + pathSeparator + "doesNotExist", 441 "output.jmod"), 442 () -> jmod("--create", 443 "--class-path", "empty" + pathSeparator + "doesNotExist", 444 "output.jmod"), 445 () -> jmod("--create", 446 "--class-path", "empty" + pathSeparator + "doesNotExist.jar", 447 "output.jmod"), 448 () -> jmod("--create", 449 "--cmds", "empty" + pathSeparator + "doesNotExist", 450 "output.jmod"), 451 () -> jmod("--create", 452 "--config", "empty" + pathSeparator + "doesNotExist", 453 "output.jmod"), 454 () -> jmod("--create", 455 "--libs", "empty" + pathSeparator + "doesNotExist", 456 "output.jmod") ); 457 458 String errMsg = "Error: path not found: doesNotExist"; 459 return tasks.stream().map(t -> new Object[] {t, errMsg} ) 460 .toArray(Object[][]::new); 461 } 462 463 @Test(dataProvider = "partOfPathDoesNotExist") 464 public void testPartOfPathNotExist(Supplier<JmodResult> supplier, 465 String errMsg) 466 { 467 supplier.get() 468 .assertFailure() 469 .resultChecker(r -> { 470 assertContains(r.output, errMsg); 471 }); 472 } 473 474 @DataProvider(name = "pathIsFile") 475 public Object[][] pathIsFile() throws IOException { 476 Path jmod = MODS_DIR.resolve("output.jmod"); 477 FileUtils.deleteFileIfExistsWithRetry(jmod); 478 Path aFile = Paths.get("aFile.txt"); 479 if (Files.exists(aFile) && !Files.isRegularFile(aFile)) 480 throw new InternalError("Unexpected file:" + aFile); 481 else 482 Files.createFile(aFile); 483 484 List<Supplier<JmodResult>> tasks = Arrays.asList( 485 () -> jmod("--create", 486 "--class-path", "aFile.txt", 487 "output.jmod"), 488 () -> jmod("--create", 489 "--modulepath", "aFile.txt", 490 "output.jmod"), 491 () -> jmod("--create", 492 "--cmds", "aFile.txt", 493 "output.jmod"), 494 () -> jmod("--create", 495 "--config", "aFile.txt", 496 "output.jmod"), 497 () -> jmod("--create", 498 "--libs", "aFile.txt", 499 "output.jmod") ); 500 501 String errMsg = "Error: path must be a directory: aFile.txt"; 502 Object[][] a = tasks.stream().map(t -> new Object[] {t, errMsg} ) 503 .toArray(Object[][]::new); 504 a[0][1] = "invalid class path entry: aFile.txt"; // class path err msg 505 return a; 506 } 507 508 @Test(dataProvider = "pathIsFile") 509 public void testPathIsFile(Supplier<JmodResult> supplier, 510 String errMsg) 511 { 512 supplier.get() 513 .assertFailure() 514 .resultChecker(r -> { 515 assertContains(r.output, errMsg); 516 }); 517 } 518 519 // --- 520 521 static boolean compileModule(String name, Path dest) throws IOException { 522 return CompilerUtils.compile(SRC_DIR.resolve(name), dest); 523 } 524 525 static void assertContains(String output, String subString) { 526 if (output.contains(subString)) 527 assertTrue(true); 528 else 529 assertTrue(false,"Expected to find [" + subString + "], in output [" 530 + output + "]"); 531 } 532 533 static JmodResult jmod(String... args) { 534 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 535 PrintStream ps = new PrintStream(baos); 536 System.out.println("jmod " + Arrays.asList(args)); 537 int ec = jdk.tools.jmod.Main.run(args, ps); 538 return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); 539 } 540 541 static class JmodResult { 542 final int exitCode; 543 final String output; 544 545 JmodResult(int exitValue, String output) { 546 this.exitCode = exitValue; 547 this.output = output; 548 } 549 JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } 550 JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; } 551 } 552 }