View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.zip;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assumptions.assumeTrue;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.nio.charset.StandardCharsets;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.nio.file.Paths;
30  import java.nio.file.StandardCopyOption;
31  
32  import org.apache.commons.io.IOUtils;
33  import org.apache.commons.lang3.SystemUtils;
34  import org.apache.commons.vfs2.FileObject;
35  import org.apache.commons.vfs2.FileSystemException;
36  import org.apache.commons.vfs2.FileSystemManager;
37  import org.apache.commons.vfs2.VFS;
38  import org.junit.jupiter.api.BeforeEach;
39  import org.junit.jupiter.api.Test;
40  
41  /**
42   * Tests https://issues.apache.org/jira/browse/VFS-291.
43   */
44  public class FileLockTest {
45  
46      private FileSystemManager manager;
47      private Path newZipFile;
48  
49      private String zipFileUri;
50  
51      private void assertDelete() throws IOException {
52          // We do not use newZipFile in the Assert message to avoid touching it before calling delete().
53          Files.delete(newZipFile);
54      }
55  
56      private void readAndAssert(final InputStream inputStream) throws IOException {
57          final String string = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
58          assertNotNull(string);
59          assertEquals("This is a test file.", string);
60      }
61  
62      private void resolveAndOpenCloseContent() throws FileSystemException {
63          try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
64              zipFileObject.getContent().close();
65          }
66      }
67  
68      private void resolveAndOpenCloseInputStream() throws IOException, FileSystemException {
69          try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
70              zipFileObject.getContent().getInputStream().close();
71          }
72      }
73  
74      private void resolveAndOpenReadCloseInputStream() throws IOException, FileSystemException {
75          try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
76              try (InputStream inputStream = zipFileObject.getContent().getInputStream()) {
77                  readAndAssert(inputStream);
78              }
79          }
80      }
81  
82      @BeforeEach
83      public void setup() throws IOException {
84          final Path zipFile = Paths.get("src/test/resources/test-data/test.zip");
85          newZipFile = Files.createTempFile(getClass().getSimpleName(), ".zip");
86          newZipFile.toFile().deleteOnExit();
87          Files.copy(zipFile, newZipFile, StandardCopyOption.REPLACE_EXISTING);
88          zipFileUri = "zip:file:" + newZipFile.toAbsolutePath() + "!/read-tests/file1.txt";
89          manager = VFS.getManager();
90      }
91  
92      @Test
93      public void testCannotDeleteWhileStreaming() throws Exception {
94          try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
95              try (InputStream inputStream = zipFileObject.getContent().getInputStream()) {
96                  if (SystemUtils.IS_OS_WINDOWS) {
97                      // We do not use newZipFile in the Assert message to avoid touching it before calling delete().
98                      assertFalse(newZipFile.toFile().delete(), "Could not delete file");
99                  }
100             }
101         }
102         assertDelete();
103     }
104 
105     @Test
106     public void testCannotDeleteWhileStreaming2() throws Exception {
107         assumeTrue(SystemUtils.IS_OS_WINDOWS);
108         try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
109             try (InputStream inputStream = zipFileObject.getContent().getInputStream()) {
110                 // We do not use newZipFile in the Assert message to avoid touching it before calling delete().
111                 assertFalse(newZipFile.toFile().delete(), "Could not delete file");
112             }
113         }
114     }
115 
116     @Test
117     public void testReadClosedFileObject() throws Exception {
118         final FileObject zipFileObjectRef;
119         try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
120             zipFileObjectRef = zipFileObject;
121             try (InputStream inputStream = zipFileObject.getContent().getInputStream()) {
122                 readAndAssert(inputStream);
123             }
124         }
125         try (InputStream inputStream = zipFileObjectRef.getContent().getInputStream()) {
126             readAndAssert(inputStream);
127         } finally {
128             zipFileObjectRef.close();
129         }
130         assertDelete();
131     }
132 
133     @Test
134     public void testResolveAndOpenCloseContent() throws Exception {
135         resolveAndOpenCloseContent();
136         assertDelete();
137     }
138 
139     @Test
140     public void testResolveAndOpenCloseContent3() throws Exception {
141         resolveAndOpenCloseContent();
142         resolveAndOpenCloseContent();
143         resolveAndOpenCloseContent();
144 
145         assertDelete();
146     }
147 
148     /**
149      * This test checks whether we can modify an underlying Zip file after we have performed IO operations on files
150      * within it, but although we no longer have any FileObjects explicitly open.
151      *
152      * @throws Exception
153      */
154     @Test
155     public void testResolveAndOpenCloseInputStream() throws Exception {
156         resolveAndOpenCloseInputStream();
157         assertDelete();
158     }
159 
160     @Test
161     public void testResolveAndOpenCloseInputStream3() throws Exception {
162         resolveAndOpenCloseInputStream();
163         resolveAndOpenCloseInputStream();
164         resolveAndOpenCloseInputStream();
165 
166         assertDelete();
167     }
168 
169     @Test
170     public void testResolveAndOpenReadCloseInputStream() throws Exception {
171         resolveAndOpenReadCloseInputStream();
172         assertDelete();
173     }
174 
175     @Test
176     public void testResolveAndOpenReadCloseInputStream3() throws Exception {
177         resolveAndOpenReadCloseInputStream();
178         resolveAndOpenReadCloseInputStream();
179         resolveAndOpenReadCloseInputStream();
180         assertDelete();
181     }
182 
183     @Test
184     public void testResolveOpenCloseNestedInputStreams() throws Exception {
185         try (FileObject zipFileObject = manager.resolveFile(zipFileUri)) {
186             try (FileObject zipFileObject2 = manager.resolveFile(zipFileUri)) {
187                 zipFileObject2.getContent().getInputStream().close();
188             }
189             zipFileObject.getContent().getInputStream().close();
190         }
191         assertDelete();
192     }
193 
194 }