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