1 /** 2 * Copyright (c) 2015, 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 * @library /test/lib 27 * @modules jdk.compiler 28 * jdk.jlink 29 * @build jdk.test.lib.compiler.CompilerUtils 30 * jdk.test.lib.util.FileUtils 31 * jdk.test.lib.Utils 32 * jdk.test.lib.Asserts 33 * jdk.test.lib.JDKToolFinder 34 * jdk.test.lib.JDKToolLauncher 35 * jdk.test.lib.Platform 36 * jdk.test.lib.process.* 37 * @run testng JmodNegativeTest 38 * @summary Negative tests for jmod 39 */ 40 41 import java.io.*; 42 import java.nio.file.Files; 43 import java.nio.file.Path; 44 import java.nio.file.Paths; 45 import java.util.Arrays; 46 import java.util.List; 47 import java.util.function.Consumer; 48 import java.util.function.Supplier; 49 import java.util.spi.ToolProvider; 50 import java.util.zip.ZipOutputStream; 51 import jdk.test.lib.util.FileUtils; 52 import jdk.test.lib.compiler.CompilerUtils; 53 import org.testng.annotations.BeforeTest; 54 import org.testng.annotations.DataProvider; 55 import org.testng.annotations.Test; 56 57 import static java.io.File.pathSeparator; 58 import static java.nio.charset.StandardCharsets.UTF_8; 59 import static org.testng.Assert.assertTrue; 60 61 public class JmodNegativeTest { 62 63 static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") 64 .orElseThrow(() -> 65 new RuntimeException("jmod tool not found") 66 ); 67 68 static final String TEST_SRC = System.getProperty("test.src", "."); 69 static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 70 static final Path EXPLODED_DIR = Paths.get("build"); 71 static final Path MODS_DIR = Paths.get("jmods"); 72 73 @BeforeTest 74 public void buildExplodedModules() throws IOException { 75 if (Files.exists(EXPLODED_DIR)) 76 FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); 77 78 for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { 79 Path dir = EXPLODED_DIR.resolve(name); 80 assertTrue(compileModule(name, dir.resolve("classes"))); 81 } 82 83 if (Files.exists(MODS_DIR)) 84 FileUtils.deleteFileTreeWithRetry(MODS_DIR); 85 Files.createDirectories(MODS_DIR); 86 } 87 88 @Test 89 public void testNoArgs() { 90 jmod() 91 .assertFailure() 92 .resultChecker(r -> 93 assertContains(r.output, "Error: one of create, extract, list, describe, or hash must be specified") 94 ); 95 } 96 97 @Test 98 public void testBadAction() { 99 jmod("badAction") 100 .assertFailure() 101 .resultChecker(r -> 102 assertContains(r.output, "Error: mode must be one of create, extract, list, describe, or hash") 103 ); 104 105 jmod("--badOption") 106 .assertFailure() 107 .resultChecker(r -> 108 assertContains(r.output, "Error: 'badOption' is not a recognized option") 109 ); 110 } 111 112 @Test 113 public void testTooManyArgs() throws IOException { 114 Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); 115 FileUtils.deleteFileIfExistsWithRetry(jmod); 116 117 jmod("create", 118 jmod.toString(), 119 "AAA") 120 .assertFailure() 121 .resultChecker(r -> 122 assertContains(r.output, "Error: unknown option(s): [AAA]") 123 ); 124 } 125 126 @Test 127 public void testCreateNoArgs() { 128 jmod("create") 129 .assertFailure() 130 .resultChecker(r -> 131 assertContains(r.output, "Error: jmod-file must be specified") 132 ); 133 } 134 135 @Test 136 public void testListNoArgs() { 137 jmod("list") 138 .assertFailure() 139 .resultChecker(r -> 140 assertContains(r.output, "Error: jmod-file must be specified") 141 ); 142 } 143 144 @Test 145 public void testListFileDoesNotExist() throws IOException { 146 Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); 147 FileUtils.deleteFileIfExistsWithRetry(jmod); 148 149 jmod("list", 150 jmod.toString()) 151 .assertFailure() 152 .resultChecker(r -> 153 assertContains(r.output, "Error: no jmod file found: " 154 + jmod.toString()) 155 ); 156 } 157 158 @Test 159 public void testListJmodIsDir() throws IOException { 160 Path jmod = MODS_DIR.resolve("testListJmodIsDir.jmod"); 161 if (Files.notExists(jmod)) 162 Files.createDirectory(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 testlistJmodMalformed() throws IOException { 174 Path jmod = MODS_DIR.resolve("testlistJmodMalformed.jmod"); 175 if (Files.notExists(jmod)) 176 Files.createFile(jmod); 177 178 jmod("list", 179 jmod.toString()) 180 .assertFailure() 181 .resultChecker(r -> 182 assertContains(r.output, "Error: error opening jmod file") 183 ); 184 } 185 186 @Test 187 public void testHashModulesModulePathNotSpecified() { 188 jmod("create", 189 "--hash-modules", "anyPattern.*", 190 "output.jmod") 191 .assertFailure() 192 .resultChecker(r -> 193 assertContains(r.output, "Error: --module-path must be " 194 +"specified when hashing modules") 195 ); 196 } 197 198 @Test 199 public void testCreateJmodAlreadyExists() throws IOException { 200 Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists.jmod"); 201 if (Files.notExists(jmod)) 202 Files.createFile(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 testCreateJmodIsDir() throws IOException { 215 Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists"); 216 if (Files.notExists(jmod)) 217 Files.createDirectory(jmod); 218 219 jmod("create", 220 "--class-path", Paths.get(".").toString(), // anything that exists 221 jmod.toString()) 222 .assertFailure() 223 .resultChecker(r -> 224 assertContains(r.output, "Error: file already exists: " + jmod.toString()) 225 ); 226 } 227 228 @Test 229 public void testInvalidModuleVersion() throws IOException { 230 Path jmod = MODS_DIR.resolve("testEmptyModuleVersion.jmod"); 231 FileUtils.deleteFileIfExistsWithRetry(jmod); 232 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 233 234 for (String version : new String[] { "", "NOT_A_VALID_VERSION" }) { 235 jmod("create", 236 "--class-path", cp, 237 "--module-version", version, 238 jmod.toString()) 239 .assertFailure() 240 .resultChecker(r -> 241 assertContains(r.output, "Error: invalid module version") 242 ); 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 testNoModuleHash() 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-modules", ".*", 331 "--module-path", emptyDir.toString(), 332 jmod.toString()) 333 .resultChecker(r -> 334 assertContains(r.output, "No hashes recorded: " + 335 "no module specified for hashing depends on foo") 336 ); 337 } 338 339 @Test 340 public void testEmptyFileInModulePath() throws IOException { 341 Path jmod = MODS_DIR.resolve("output.jmod"); 342 FileUtils.deleteFileIfExistsWithRetry(jmod); 343 Path empty = MODS_DIR.resolve("emptyFile.jmod"); 344 FileUtils.deleteFileIfExistsWithRetry(empty); 345 Files.createFile(empty); 346 try { 347 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 348 349 jmod("create", 350 "--class-path", cp, 351 "--hash-modules", ".*", 352 "--module-path", MODS_DIR.toString(), 353 jmod.toString()) 354 .assertFailure(); 355 } finally { 356 FileUtils.deleteFileWithRetry(empty); 357 } 358 } 359 360 @Test 361 public void testFileInModulePath() throws IOException { 362 Path jmod = MODS_DIR.resolve("output.jmod"); 363 FileUtils.deleteFileIfExistsWithRetry(jmod); 364 Path file = MODS_DIR.resolve("testFileInModulePath.txt"); 365 FileUtils.deleteFileIfExistsWithRetry(file); 366 Files.createFile(file); 367 368 jmod("create", 369 "--hash-modules", ".*", 370 "--module-path", file.toString(), 371 jmod.toString()) 372 .assertFailure() 373 .resultChecker(r -> 374 assertContains(r.output, "Error: path must be a directory") 375 ); 376 } 377 378 @DataProvider(name = "pathDoesNotExist") 379 public Object[][] pathDoesNotExist() throws IOException { 380 Path jmod = MODS_DIR.resolve("output.jmod"); 381 FileUtils.deleteFileIfExistsWithRetry(jmod); 382 FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); 383 384 List<Supplier<JmodResult>> tasks = Arrays.asList( 385 () -> jmod("create", 386 "--hash-modules", "anyPattern", 387 "--module-path", "doesNotExist", 388 "output.jmod"), 389 () -> jmod("create", 390 "--class-path", "doesNotExist", 391 "output.jmod"), 392 () -> jmod("create", 393 "--class-path", "doesNotExist.jar", 394 "output.jmod"), 395 () -> jmod("create", 396 "--cmds", "doesNotExist", 397 "output.jmod"), 398 () -> jmod("create", 399 "--config", "doesNotExist", 400 "output.jmod"), 401 () -> jmod("create", 402 "--libs", "doesNotExist", 403 "output.jmod") ); 404 405 String errMsg = "Error: path not found: doesNotExist"; 406 return tasks.stream().map(t -> new Object[] {t, errMsg} ) 407 .toArray(Object[][]::new); 408 } 409 410 @Test(dataProvider = "pathDoesNotExist") 411 public void testPathDoesNotExist(Supplier<JmodResult> supplier, 412 String errMsg) 413 { 414 supplier.get() 415 .assertFailure() 416 .resultChecker(r -> { 417 assertContains(r.output, errMsg); 418 }); 419 } 420 421 @DataProvider(name = "partOfPathDoesNotExist") 422 public Object[][] partOfPathDoesNotExist() throws IOException { 423 Path jmod = MODS_DIR.resolve("output.jmod"); 424 FileUtils.deleteFileIfExistsWithRetry(jmod); 425 FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); 426 427 Path emptyDir = Paths.get("empty"); 428 if (Files.exists(emptyDir)) 429 FileUtils.deleteFileTreeWithRetry(emptyDir); 430 Files.createDirectory(emptyDir); 431 432 List<Supplier<JmodResult>> tasks = Arrays.asList( 433 () -> jmod("create", 434 "--hash-modules", "anyPattern", 435 "--module-path","empty" + pathSeparator + "doesNotExist", 436 "output.jmod"), 437 () -> jmod("create", 438 "--class-path", "empty" + pathSeparator + "doesNotExist", 439 "output.jmod"), 440 () -> jmod("create", 441 "--class-path", "empty" + pathSeparator + "doesNotExist.jar", 442 "output.jmod"), 443 () -> jmod("create", 444 "--cmds", "empty" + pathSeparator + "doesNotExist", 445 "output.jmod"), 446 () -> jmod("create", 447 "--config", "empty" + pathSeparator + "doesNotExist", 448 "output.jmod"), 449 () -> jmod("create", 450 "--libs", "empty" + pathSeparator + "doesNotExist", 451 "output.jmod") ); 452 453 String errMsg = "Error: path not found: doesNotExist"; 454 return tasks.stream().map(t -> new Object[] {t, errMsg} ) 455 .toArray(Object[][]::new); 456 } 457 458 @Test(dataProvider = "partOfPathDoesNotExist") 459 public void testPartOfPathNotExist(Supplier<JmodResult> supplier, 460 String errMsg) 461 { 462 supplier.get() 463 .assertFailure() 464 .resultChecker(r -> { 465 assertContains(r.output, errMsg); 466 }); 467 } 468 469 @DataProvider(name = "pathIsFile") 470 public Object[][] pathIsFile() throws IOException { 471 Path jmod = MODS_DIR.resolve("output.jmod"); 472 FileUtils.deleteFileIfExistsWithRetry(jmod); 473 Path aFile = Paths.get("aFile.txt"); 474 if (Files.exists(aFile) && !Files.isRegularFile(aFile)) 475 throw new InternalError("Unexpected file:" + aFile); 476 else 477 Files.createFile(aFile); 478 479 List<Supplier<JmodResult>> tasks = Arrays.asList( 480 () -> jmod("create", 481 "--class-path", "aFile.txt", 482 "output.jmod"), 483 () -> jmod("create", 484 "--module-path", "aFile.txt", 485 "output.jmod"), 486 () -> jmod("create", 487 "--cmds", "aFile.txt", 488 "output.jmod"), 489 () -> jmod("create", 490 "--config", "aFile.txt", 491 "output.jmod"), 492 () -> jmod("create", 493 "--libs", "aFile.txt", 494 "output.jmod") ); 495 496 String errMsg = "Error: path must be a directory: aFile.txt"; 497 Object[][] a = tasks.stream().map(t -> new Object[] {t, errMsg} ) 498 .toArray(Object[][]::new); 499 a[0][1] = "invalid class path entry: aFile.txt"; // class path err msg 500 return a; 501 } 502 503 @Test(dataProvider = "pathIsFile") 504 public void testPathIsFile(Supplier<JmodResult> supplier, 505 String errMsg) 506 { 507 supplier.get() 508 .assertFailure() 509 .resultChecker(r -> { 510 assertContains(r.output, errMsg); 511 }); 512 } 513 514 // --- 515 516 static boolean compileModule(String name, Path dest) throws IOException { 517 return CompilerUtils.compile(SRC_DIR.resolve(name), dest); 518 } 519 520 static void assertContains(String output, String subString) { 521 if (output.contains(subString)) 522 assertTrue(true); 523 else 524 assertTrue(false,"Expected to find [" + subString + "], in output [" 525 + output + "]"); 526 } 527 528 static JmodResult jmod(String... args) { 529 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 530 PrintStream ps = new PrintStream(baos); 531 System.out.println("jmod " + Arrays.asList(args)); 532 int ec = JMOD_TOOL.run(ps, ps, args); 533 return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); 534 } 535 536 static class JmodResult { 537 final int exitCode; 538 final String output; 539 540 JmodResult(int exitValue, String output) { 541 this.exitCode = exitValue; 542 this.output = output; 543 } 544 JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } 545 JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; } 546 } 547 }