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