1 /* 2 * Copyright (c) 2014, 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 * @summary Basic test of jrt file system provider 27 * @run testng Basic 28 */ 29 30 import java.io.InputStream; 31 import java.io.DataInputStream; 32 import java.nio.file.DirectoryStream; 33 import java.nio.file.Files; 34 import java.nio.file.FileSystem; 35 import java.nio.file.FileSystems; 36 import java.nio.file.Path; 37 import java.nio.file.PathMatcher; 38 import java.nio.file.Paths; 39 import java.net.URI; 40 import java.util.Collections; 41 import java.util.Iterator; 42 import java.util.Map; 43 import java.util.NoSuchElementException; 44 import java.util.stream.Stream; 45 46 import org.testng.annotations.DataProvider; 47 import org.testng.annotations.Test; 48 49 import static org.testng.Assert.assertEquals; 50 import static org.testng.Assert.assertNotEquals; 51 import static org.testng.Assert.assertTrue; 52 import static org.testng.Assert.assertFalse; 53 54 /** 55 * Basic tests for jrt:/ file system provider. 56 */ 57 58 public class Basic { 59 60 // Checks that the given FileSystem is a jrt file system. 61 private void checkFileSystem(FileSystem fs) { 62 assertTrue(fs.provider().getScheme().equalsIgnoreCase("jrt")); 63 assertTrue(fs.isOpen()); 64 assertTrue(fs.isReadOnly()); 65 assertEquals(fs.getSeparator(), "/"); 66 67 // one root 68 Iterator<Path> roots = fs.getRootDirectories().iterator(); 69 assertTrue(roots.next().toString().equals("/")); 70 assertFalse(roots.hasNext()); 71 } 72 73 @Test 74 public void testGetFileSystem() { 75 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 76 checkFileSystem(fs); 77 78 // getFileSystem should return the same object each time 79 assertTrue(fs == FileSystems.getFileSystem(URI.create("jrt:/"))); 80 } 81 82 @Test(expectedExceptions = UnsupportedOperationException.class) 83 public void testCloseFileSystem() throws Exception { 84 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 85 fs.close(); // should throw UOE 86 } 87 88 @Test 89 public void testNewFileSystem() throws Exception { 90 FileSystem theFileSystem = FileSystems.getFileSystem(URI.create("jrt:/")); 91 Map<String, ?> env = Collections.emptyMap(); 92 try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env)) { 93 checkFileSystem(fs); 94 assertTrue(fs != theFileSystem); 95 } 96 } 97 98 @DataProvider(name = "knownClassFiles") 99 private Object[][] knownClassFiles() { 100 return new Object[][] { 101 { "/modules/java.base/java/lang/Object.class" }, 102 { "modules/java.base/java/lang/Object.class" }, 103 }; 104 } 105 106 @Test(dataProvider = "knownClassFiles") 107 public void testKnownClassFiles(String path) throws Exception { 108 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 109 Path classFile = fs.getPath(path); 110 111 assertTrue(Files.isRegularFile(classFile)); 112 assertTrue(Files.size(classFile) > 0L); 113 114 // check magic number 115 try (InputStream in = Files.newInputStream(classFile)) { 116 int magic = new DataInputStream(in).readInt(); 117 assertEquals(magic, 0xCAFEBABE); 118 } 119 } 120 121 @DataProvider(name = "knownDirectories") 122 private Object[][] knownDirectories() { 123 return new Object[][] { 124 { "/" }, 125 { "." }, 126 { "./" }, 127 { "/." }, 128 { "/./" }, 129 { "/modules/java.base/.." }, 130 { "/modules/java.base/../" }, 131 { "/modules/java.base/../." }, 132 { "/modules/java.base" }, 133 { "/modules/java.base/java/lang" }, 134 { "modules/java.base/java/lang" }, 135 { "/modules/java.base/java/lang/" }, 136 { "modules/java.base/java/lang/" } 137 }; 138 } 139 140 @Test(dataProvider = "knownDirectories") 141 public void testKnownDirectories(String path) throws Exception { 142 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 143 Path dir = fs.getPath(path); 144 145 assertTrue(Files.isDirectory(dir)); 146 147 // directory should not be empty 148 try (Stream<Path> stream = Files.list(dir)) { 149 assertTrue(stream.count() > 0L); 150 } 151 try (Stream<Path> stream = Files.walk(dir)) { 152 assertTrue(stream.count() > 0L); 153 } 154 } 155 156 @DataProvider(name = "topLevelPkgDirs") 157 private Object[][] topLevelPkgDirs() { 158 return new Object[][] { 159 { "/java/lang" }, 160 { "java/lang" }, 161 { "/java/util" }, 162 { "java/util" }, 163 }; 164 } 165 166 @Test(dataProvider = "topLevelPkgDirs") 167 public void testNotExists(String path) throws Exception { 168 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 169 Path dir = fs.getPath(path); 170 171 // package directories should not be there at top level 172 assertTrue(Files.notExists(dir)); 173 } 174 175 /** 176 * Test the URI of every file in the jrt file system 177 */ 178 @Test 179 public void testToAndFromUri() throws Exception { 180 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 181 Path top = fs.getPath("/"); 182 try (Stream<Path> stream = Files.walk(top)) { 183 stream.forEach(path -> { 184 URI u = path.toUri(); 185 assertTrue(u.getScheme().equalsIgnoreCase("jrt")); 186 assertFalse(u.isOpaque()); 187 assertTrue(u.getAuthority() == null); 188 assertEquals(u.getPath(), path.toAbsolutePath().toString()); 189 Path p = Paths.get(u); 190 assertEquals(p, path); 191 }); 192 } 193 } 194 195 @Test 196 public void testDirectoryNames() throws Exception { 197 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 198 Path top = fs.getPath("/"); 199 // check that directory names do not have trailing '/' char 200 try (Stream<Path> stream = Files.walk(top)) { 201 stream.skip(1).filter(Files::isDirectory).forEach(path -> { 202 assertFalse(path.toString().endsWith("/")); 203 }); 204 } 205 } 206 207 @DataProvider(name = "pathPrefixs") 208 private Object[][] pathPrefixes() { 209 return new Object[][] { 210 { "/" }, 211 { "modules/java.base/java/lang" }, 212 { "./modules/java.base/java/lang" }, 213 { "/modules/java.base/java/lang" }, 214 { "/./modules/java.base/java/lang" }, 215 { "modules/java.base/java/lang/" }, 216 { "./modules/java.base/java/lang/" }, 217 { "/./modules/java.base/java/lang/" }, 218 }; 219 } 220 221 // @Test(dataProvider = "pathPrefixes") 222 public void testParentInDirList(String dir) throws Exception { 223 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 224 Path base = fs.getPath(dir); 225 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 226 for (Path entry: stream) { 227 assertTrue( entry.getParent().equals(base), 228 base.toString() + "-> " + entry.toString() ); 229 } 230 } 231 } 232 233 @DataProvider(name = "dirStreamStringFilterData") 234 private Object[][] dirStreamStringFilterData() { 235 return new Object[][] { 236 { "/modules/java.base/java/lang", "/reflect" }, 237 { "/modules/java.base/java/lang", "/Object.class" }, 238 { "/modules/java.base/java/util", "/stream" }, 239 { "/modules/java.base/java/util", "/List.class" }, 240 }; 241 } 242 243 @Test(dataProvider = "dirStreamStringFilterData") 244 public void testDirectoryStreamStringFilter(String dir, String filter) throws Exception { 245 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 246 Path base = fs.getPath(dir); 247 try (DirectoryStream<Path> stream = 248 Files.newDirectoryStream(base, p->!p.toString().endsWith(filter))) { 249 for (Path entry: stream) { 250 assertFalse(entry.toString().contains(filter), 251 "filtered path seen: " + filter); 252 } 253 } 254 255 // make sure without filter, we do see that matching entry! 256 boolean seen = false; 257 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 258 for (Path entry: stream) { 259 if (entry.toString().endsWith(filter)) { 260 seen = true; 261 break; 262 } 263 } 264 } 265 266 assertTrue(seen, "even without filter " + filter + " is missing"); 267 } 268 269 @DataProvider(name = "dirStreamFilterData") 270 private Object[][] dirStreamFilterData() { 271 return new Object[][] { 272 { 273 "/", 274 (DirectoryStream.Filter<Path>)(Files::isDirectory), 275 "isDirectory" 276 }, 277 { 278 "/modules/java.base/java/lang", 279 (DirectoryStream.Filter<Path>)(Files::isRegularFile), 280 "isFile" 281 } 282 }; 283 } 284 285 @Test(dataProvider = "dirStreamFilterData") 286 private void testDirectoryStreamFilter(String dir, DirectoryStream.Filter filter, 287 String name) throws Exception { 288 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 289 Path base = fs.getPath(dir); 290 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base, filter)) { 291 for (Path entry: stream) { 292 assertTrue(filter.accept(entry), "filtered path seen: " + name); 293 } 294 } 295 296 // make sure without filter, we do see that matching entry! 297 boolean seen = false; 298 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 299 for (Path entry: stream) { 300 if (filter.accept(entry)) { 301 seen = true; 302 break; 303 } 304 } 305 } 306 307 assertTrue(seen, "even without filter " + name + " is missing"); 308 } 309 310 @Test 311 private void testDirectoryStreamIterator() throws Exception { 312 // run the tests with null filter (no filter) 313 dirStreamIteratorTest(null); 314 // run the same tests with trivial "accept all" filter 315 dirStreamIteratorTest(p->true); 316 // two other non-trivial ones 317 dirStreamIteratorTest(Files::isDirectory); 318 dirStreamIteratorTest(Files::isRegularFile); 319 } 320 321 private void dirStreamIteratorTest(DirectoryStream.Filter<Path> filter) 322 throws Exception { 323 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 324 // This test assumes at least there are two elements in "java/lang" 325 // package with any filter passed. don't change to different path here! 326 Path dir = fs.getPath("/modules/java.base/java/lang"); 327 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 328 Iterator<Path> itr = stream.iterator(); 329 itr.hasNext(); 330 Path path1 = itr.next(); 331 // missing second hasNext call 332 Path path2 = itr.next(); 333 assertNotEquals(path1, path2); 334 } 335 336 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 337 Iterator<Path> itr = stream.iterator(); 338 // no hasNext calls at all 339 Path path1 = itr.next(); 340 Path path2 = itr.next(); 341 assertNotEquals(path1, path2); 342 } 343 344 int numEntries = 0; 345 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 346 Iterator<Path> itr = stream.iterator(); 347 while (itr.hasNext()) { 348 numEntries++; 349 itr.next(); 350 } 351 352 // reached EOF, next call should result in exception 353 try { 354 itr.next(); 355 throw new AssertionError("should have thrown exception"); 356 } catch (NoSuchElementException nsee) { 357 System.out.println("got NoSuchElementException as expected"); 358 } 359 } 360 361 // redundant hasNext calls 362 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 363 Iterator<Path> itr = stream.iterator(); 364 // any number of hasNext should definitely stay at first element 365 for (int i = 0; i < 2*numEntries; i++) { 366 itr.hasNext(); 367 } 368 369 for (int j = 0; j < numEntries; j++) { 370 itr.next(); 371 } 372 // exactly count number of entries! 373 assertFalse(itr.hasNext()); 374 } 375 } 376 377 @DataProvider(name = "hiddenPaths") 378 private Object[][] hiddenPaths() { 379 return new Object[][] { 380 { "/META-INF" }, 381 { "/META-INF/services" }, 382 { "/META-INF/services/java.nio.file.spi.FileSystemProvider" }, 383 { "/modules/java.base/packages.offsets" }, 384 { "/modules/java.instrument/packages.offsets" }, 385 { "/modules/jdk.zipfs/packages.offsets" }, 386 { "/java/lang" }, 387 { "/java/util" }, 388 }; 389 } 390 391 @Test(dataProvider = "hiddenPaths") 392 public void testHiddenPathsNotExposed(String path) throws Exception { 393 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 394 assertTrue(Files.notExists(fs.getPath(path)), path + " should not exist"); 395 } 396 397 @DataProvider(name = "pathGlobPatterns") 398 private Object[][] pathGlobPatterns() { 399 return new Object[][] { 400 { "/modules/*", "/modules/java.base", true }, 401 { "/modules/*", "/modules/java.base/java", false }, 402 { "/modules/j*", "/modules/java.base", true }, 403 { "/modules/J*", "/modules/java.base", false }, 404 { "**.class", "/modules/java.base/java/lang/Object.class", true }, 405 { "**.java", "/modules/java.base/java/lang/Object.class", false }, 406 { "**java/*", "/modules/java.base/java/lang", true }, 407 { "**java/lang/ref*", "/modules/java.base/java/lang/reflect", true }, 408 { "**java/lang/ref*", "/modules/java.base/java/lang/ref", true }, 409 { "**java/lang/ref?", "/modules/java.base/java/lang/ref", false }, 410 { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/ref", true }, 411 { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/reflect", true }, 412 { "**java/[a-u]?*/*.class", "/modules/java.base/java/util/Map.class", true }, 413 { "**java/util/[a-z]*.class", "/modules/java.base/java/util/TreeMap.class", false }, 414 }; 415 } 416 417 @Test(dataProvider = "pathGlobPatterns") 418 public void testGlobPathMatcher(String pattern, String path, 419 boolean expectMatch) throws Exception { 420 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 421 PathMatcher pm = fs.getPathMatcher("glob:" + pattern); 422 Path p = fs.getPath(path); 423 assertTrue(Files.exists(p), path); 424 assertTrue(!(pm.matches(p) ^ expectMatch), 425 p + (expectMatch? " should match " : " should not match ") + 426 pattern); 427 } 428 429 @DataProvider(name = "pathRegexPatterns") 430 private Object[][] pathRegexPatterns() { 431 return new Object[][] { 432 { "/modules/.*", "/modules/java.base", true }, 433 { "/modules/[^/]*", "/modules/java.base/java", false }, 434 { "/modules/j.*", "/modules/java.base", true }, 435 { "/modules/J.*", "/modules/java.base", false }, 436 { ".*\\.class", "/modules/java.base/java/lang/Object.class", true }, 437 { ".*\\.java", "/modules/java.base/java/lang/Object.class", false }, 438 { ".*java/.*", "/modules/java.base/java/lang", true }, 439 { ".*java/lang/ref.*", "/modules/java.base/java/lang/reflect", true }, 440 { ".*java/lang/ref.*", "/modules/java.base/java/lang/ref", true }, 441 { ".*/java/lang/ref.+", "/modules/java.base/java/lang/ref", false }, 442 { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/ref", true }, 443 { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/reflect", true }, 444 { ".*/java/[a-u]?.*/.*\\.class", "/modules/java.base/java/util/Map.class", true }, 445 { ".*/java/util/[a-z]*\\.class", "/modules/java.base/java/util/TreeMap.class", false }, 446 }; 447 } 448 449 @Test(dataProvider = "pathRegexPatterns") 450 public void testRegexPathMatcher(String pattern, String path, 451 boolean expectMatch) throws Exception { 452 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 453 PathMatcher pm = fs.getPathMatcher("regex:" + pattern); 454 Path p = fs.getPath(path); 455 assertTrue(Files.exists(p), path); 456 assertTrue(!(pm.matches(p) ^ expectMatch), 457 p + (expectMatch? " should match " : " should not match ") + 458 pattern); 459 } 460 461 @Test 462 public void testPackagesAndModules() throws Exception { 463 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 464 assertTrue(Files.isDirectory(fs.getPath("/packages"))); 465 assertTrue(Files.isDirectory(fs.getPath("/modules"))); 466 } 467 468 @DataProvider(name = "packagesSubDirs") 469 private Object[][] packagesSubDirs() { 470 return new Object[][] { 471 { "java.lang" }, 472 { "java.util" }, 473 { "java.nio" }, 474 { "jdk.nashorn.api.scripting" } 475 }; 476 } 477 478 @Test(dataProvider = "packagesSubDirs") 479 public void testPackagesSubDirs(String pkg) throws Exception { 480 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 481 assertTrue(Files.isDirectory(fs.getPath("/packages/" + pkg)), 482 pkg + " missing"); 483 } 484 485 @DataProvider(name = "packagesLinks") 486 private Object[][] packagesLinks() { 487 return new Object[][] { 488 { "/packages/java.lang/java.base" }, 489 { "/packages/java.lang/java.instrument" }, 490 { "/packages/java/java.base" }, 491 { "/packages/java/java.instrument" }, 492 { "/packages/java/java.rmi" }, 493 { "/packages/java/java.sql" }, 494 { "/packages/javax/java.base" }, 495 { "/packages/javax/java.sql" }, 496 { "/packages/javax/java.xml" }, 497 { "/packages/javax/java.management" }, 498 { "/packages/java.util/java.base" }, 499 { "/packages/jdk.nashorn.api.scripting/jdk.scripting.nashorn" }, 500 }; 501 } 502 503 @Test(dataProvider = "packagesLinks") 504 public void testPackagesLinks(String link) throws Exception { 505 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 506 Path path = fs.getPath(link); 507 assertTrue(Files.exists(path), link + " missing"); 508 assertTrue(Files.isSymbolicLink(path), path + " is not a link"); 509 path = Files.readSymbolicLink(path); 510 assertEquals(path.toString(), "/modules" + link.substring(link.lastIndexOf("/"))); 511 } 512 513 @DataProvider(name = "modulesSubDirs") 514 private Object[][] modulesSubDirs() { 515 return new Object[][] { 516 { "java.base" }, 517 { "java.sql" }, 518 { "jdk.scripting.nashorn" }, 519 }; 520 } 521 522 @Test(dataProvider = "modulesSubDirs") 523 public void testModulesSubDirs(String module) throws Exception { 524 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 525 Path path = fs.getPath("/modules/" + module); 526 assertTrue(Files.isDirectory(path), module + " missing"); 527 assertTrue(!Files.isSymbolicLink(path), path + " is a link"); 528 } 529 530 @DataProvider(name="linkChases") 531 private Object[][] linkChases() { 532 return new Object[][] { 533 { "/modules/java.base/java/lang" }, 534 { "/modules/java.base/java/util/Vector.class" }, 535 { "/modules/jdk.scripting.nashorn/jdk/nashorn" }, 536 { "/packages/java.lang/java.base/java/lang" }, 537 { "/packages/java.util/java.base/java/util/Vector.class" }, 538 }; 539 } 540 541 @Test(dataProvider = "linkChases") 542 public void testLinkChases(String link) throws Exception { 543 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 544 Path path = fs.getPath(link); 545 assertTrue(Files.exists(path), link); 546 } 547 548 @Test 549 public void testSymlinkDirList() throws Exception { 550 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 551 Path path = fs.getPath("/packages/java.lang/java.base"); 552 assertTrue(Files.isSymbolicLink(path)); 553 assertTrue(Files.isDirectory(path)); 554 555 boolean javaSeen = false, javaxSeen = false; 556 try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { 557 for (Path p : stream) { 558 String str = p.toString(); 559 if (str.endsWith("/java")) { 560 javaSeen = true; 561 } else if (str.endsWith("javax")) { 562 javaxSeen = true; 563 } 564 } 565 } 566 assertTrue(javaSeen); 567 assertTrue(javaxSeen); 568 } 569 570 @Test 571 public void testPackagesSubDirList() throws Exception { 572 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 573 String pathName = "/packages/javax.annotation"; 574 Path path = fs.getPath(pathName); 575 boolean seenJavaCompiler = false, seenAnnotationsCommon = false; 576 try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { 577 for (Path p : stream) { 578 String str = p.toString(); 579 if (str.equals(pathName + "/java.compiler")) { 580 seenJavaCompiler = true; 581 } else if (str.equals(pathName + "/java.annotations.common")) { 582 seenAnnotationsCommon = true; 583 } 584 } 585 } 586 assertTrue(seenJavaCompiler); 587 assertTrue(seenAnnotationsCommon); 588 } 589 590 @Test 591 public void testRootDirList() throws Exception { 592 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 593 Path path = fs.getPath("/"); 594 // check /packages and /modules are not repeated 595 // and seen once. 596 boolean packages = false, modules = false; 597 try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { 598 for (Path p : stream) { 599 String str = p.toString(); 600 switch (str) { 601 case "/packages": 602 assertFalse(packages, "/packages repeated"); 603 packages = true; 604 break; 605 case "/modules": 606 assertFalse(modules, "/modules repeated"); 607 modules = true; 608 break; 609 } 610 } 611 } 612 assertTrue(packages, "/packages missing in / list!"); 613 assertTrue(modules, "/modules missing in / list!"); 614 } 615 }