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