@@ -40,20 +40,114 @@ void closedFileSystemException() throws IOException, InterruptedException, Execu
4040 });
4141 }
4242
43- static void stress (Consumer <OpenPathTree > consumer ) throws IOException {
44- /* Find assertj-core jar in the class path */
43+ @ Test
44+ void untrackedWalkDoesNotBreakSharedFs () throws IOException {
45+ /*
46+ * Tests that calling walk() on a SharedArchivePathTree (which inherits
47+ * ArchivePathTree.walk() and opens/closes a temporary ZipFS) does not
48+ * corrupt the shared ZipFS obtained via open().
49+ */
50+ final Path jar = copyAssertjCoreJar ();
51+ final ArchivePathTree tree = SharedArchivePathTree .forPath (jar );
52+
53+ // Step 1: open a shared ZipFS
54+ try (OpenPathTree shared = tree .open ()) {
55+ // Step 2: call inherited walk() — opens and closes a temp ZipFS
56+ tree .walk (visit -> {
57+ // just iterate, don't need to do anything
58+ });
59+
60+ // Step 3: read from the shared ZipFS — should still work
61+ Path p = shared .getPath ("org/assertj/core/api/Assertions.class" );
62+ Assertions .assertThat (p ).isNotNull ();
63+ byte [] bytes = Files .readAllBytes (p );
64+ Assertions .assertThat (bytes ).isNotEmpty ();
65+ }
66+ }
67+
68+ @ Test
69+ void untrackedWalkRawDoesNotBreakSharedFs () throws IOException {
70+ final Path jar = copyAssertjCoreJar ();
71+ final ArchivePathTree tree = SharedArchivePathTree .forPath (jar );
72+
73+ try (OpenPathTree shared = tree .open ()) {
74+ tree .walkRaw (visit -> {
75+ });
76+
77+ Path p = shared .getPath ("org/assertj/core/api/Assertions.class" );
78+ Assertions .assertThat (p ).isNotNull ();
79+ byte [] bytes = Files .readAllBytes (p );
80+ Assertions .assertThat (bytes ).isNotEmpty ();
81+ }
82+ }
83+
84+ @ Test
85+ void multipleUntrackedWalksDoNotBreakSharedFs () throws IOException {
86+ final Path jar = copyAssertjCoreJar ();
87+ final ArchivePathTree tree = SharedArchivePathTree .forPath (jar );
88+
89+ try (OpenPathTree shared = tree .open ()) {
90+ // Multiple untracked walks
91+ for (int i = 0 ; i < 5 ; i ++) {
92+ tree .walk (visit -> {
93+ });
94+ }
95+
96+ Path p = shared .getPath ("org/assertj/core/api/Assertions.class" );
97+ Assertions .assertThat (p ).isNotNull ();
98+ byte [] bytes = Files .readAllBytes (p );
99+ Assertions .assertThat (bytes ).isNotEmpty ();
100+ }
101+ }
102+
103+ @ Test
104+ void concurrentUntrackedWalkDoesNotBreakSharedFs () throws IOException , InterruptedException , ExecutionException {
105+ final Path jar = copyAssertjCoreJar ();
106+ final ArchivePathTree tree = SharedArchivePathTree .forPath (jar );
107+
108+ try (OpenPathTree shared = tree .open ()) {
109+ // Concurrently walk (untracked) while holding the shared ZipFS open
110+ final ExecutorService executor = Executors .newFixedThreadPool (8 );
111+ final List <Future <Void >> futures = new ArrayList <>(8 );
112+ try {
113+ for (int i = 0 ; i < 8 ; i ++) {
114+ futures .add (executor .submit (() -> {
115+ tree .walk (visit -> {
116+ });
117+ return null ;
118+ }));
119+ }
120+ for (Future <Void > f : futures ) {
121+ Assertions .assertThat (f ).succeedsWithin (30 , TimeUnit .SECONDS );
122+ }
123+ } finally {
124+ executor .shutdown ();
125+ }
126+
127+ // The shared ZipFS should still be usable
128+ Path p = shared .getPath ("org/assertj/core/api/Assertions.class" );
129+ Assertions .assertThat (p ).isNotNull ();
130+ byte [] bytes = Files .readAllBytes (p );
131+ Assertions .assertThat (bytes ).isNotEmpty ();
132+ }
133+ }
134+
135+ private static Path copyAssertjCoreJar () throws IOException {
45136 final String rawCp = System .getProperty ("java.class.path" );
46137 final String assertjCoreJarPath = Stream .of (rawCp .split (System .getProperty ("path.separator" )))
47138 .filter (p -> p .contains ("assertj-core" ))
48139 .findFirst ()
49- .orElseThrow (() -> new AssertionError ("Could not find assertj-core in " + rawCp ));
50-
51- /* Create a copy of assertj-core jar in target directory */
52- final Path assertjCoreJarPathCopy = Path .of ("target/assertj-core-" + UUID .randomUUID () + ".jar" );
53- if (!Files .exists (assertjCoreJarPathCopy .getParent ())) {
54- Files .createDirectories (assertjCoreJarPathCopy .getParent ());
140+ .orElseThrow (() -> new AssertionError ("Could not find assertj-core in " + rawCp ));
141+ final Path copy = Path .of ("target/assertj-core-" + UUID .randomUUID () + ".jar" );
142+ if (!Files .exists (copy .getParent ())) {
143+ Files .createDirectories (copy .getParent ());
55144 }
56- Files .copy (Path .of (assertjCoreJarPath ), assertjCoreJarPathCopy );
145+ Files .copy (Path .of (assertjCoreJarPath ), copy );
146+ return copy ;
147+ }
148+
149+ static void stress (Consumer <OpenPathTree > consumer ) throws IOException {
150+ final Path assertjCoreJarPathCopy = copyAssertjCoreJar ();
57151
58152 /* Now do some concurrent opening and closing of the SharedArchivePathTree instance */
59153 final ArchivePathTree archivePathTree = SharedArchivePathTree .forPath (assertjCoreJarPathCopy );
0 commit comments