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