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