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