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.ram;
18  
19  import static org.junit.Assert.assertArrayEquals;
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertNotSame;
23  import static org.junit.Assert.assertSame;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.Closeable;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.List;
34  
35  import org.apache.commons.vfs2.AllFileSelector;
36  import org.apache.commons.vfs2.FileContent;
37  import org.apache.commons.vfs2.FileObject;
38  import org.apache.commons.vfs2.FileSystemException;
39  import org.apache.commons.vfs2.FileSystemOptions;
40  import org.apache.commons.vfs2.FileType;
41  import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
42  import org.apache.commons.vfs2.provider.UriParser;
43  import org.junit.After;
44  import org.junit.Assert;
45  import org.junit.Before;
46  import org.junit.Test;
47  
48  /**
49   * Custom tests for RamProvider.
50   */
51  public class CustomRamProviderTest {
52      private static final byte[] NON_EMPTY_FILE_CONTENT = new byte[] { 1, 2, 3 };
53  
54      /** List of URL special characters encoded for AbstractFileObject#getChild */
55      final char[] ENC = { /*'#',*/ '!', '?'};
56  
57      private final List<Closeable> closeables = new ArrayList<>();
58  
59      FileSystemOptions defaultRamFso = new FileSystemOptions();
60  
61      DefaultFileSystemManager manager;
62  
63      FileSystemOptions smallSizedFso = new FileSystemOptions();
64  
65      FileSystemOptions zeroSizedFso = new FileSystemOptions();
66  
67      /**
68       * Closes the given {@link Closeable} during the tearDown phase.
69       */
70      private <C extends Closeable> C closeOnTearDown(final C closeable) {
71          this.closeables.add(closeable);
72          return closeable;
73      }
74  
75      private InputStream createEmptyFile() throws FileSystemException, IOException {
76          final FileObject root = manager.resolveFile("ram://file");
77          root.createFile();
78          return this.closeOnTearDown(root.getContent().getInputStream());
79      }
80  
81      private InputStream createNonEmptyFile() throws FileSystemException, IOException {
82          final FileObject root = manager.resolveFile("ram://file");
83          root.createFile();
84  
85          final FileContent content = root.getContent();
86          final OutputStream output = this.closeOnTearDown(content.getOutputStream());
87          output.write(1);
88          output.write(2);
89          output.write(3);
90          output.flush();
91          output.close();
92  
93          return this.closeOnTearDown(content.getInputStream());
94      }
95  
96      /** Create directory structure for {@link #testSpecialName()} and {@link #testSchemePrefix()} */
97      private FileObject prepareSpecialFile(final String dirname, final String testFileName) throws FileSystemException
98      {
99          // set up a folder containing an filename with special characters:
100         final FileObject dir = manager.resolveFile("ram:" + dirname);
101         dir.createFolder();
102         // construct the absolute name to make sure the relative name is not miss-interpreted
103         // ("./" + UriParser.encode(testFileName, ENC) would also work)
104         final String filePath = dir.getName().getPath() + "/" + UriParser.encode(testFileName, ENC);
105 
106         final FileObject specialFile = dir.resolveFile(filePath);
107         specialFile.createFile();
108 
109         return dir;
110     }
111 
112 
113     @Before
114     public void setUp() throws Exception {
115         manager = new DefaultFileSystemManager();
116         manager.addProvider("ram", new RamFileProvider());
117         manager.init();
118 
119         // File Systems Options
120         RamFileSystemConfigBuilder.getInstance().setMaxSize(zeroSizedFso, 0L);
121         RamFileSystemConfigBuilder.getInstance().setMaxSize(smallSizedFso, 10L);
122     }
123 
124     @After
125     public void tearDown() {
126         for (final Closeable closeable : this.closeables) {
127             try {
128                 closeable.close();
129             } catch (final Exception e) {
130                 // ignore
131             }
132         }
133         manager.close();
134     }
135 
136     @Test
137     public void testFSOptions() throws Exception {
138         // Default FS
139         final FileObject fo1 = manager.resolveFile("ram:/");
140         final FileObject fo2 = manager.resolveFile("ram:/");
141         assertSame("Both files should exist in the same fs instance.", fo1.getFileSystem(), fo2.getFileSystem());
142 
143         FileSystemOptions fsOptions = fo1.getFileSystem().getFileSystemOptions();
144         long maxFilesystemSize = RamFileSystemConfigBuilder.getInstance().getLongMaxSize(fsOptions);
145         assertEquals("Filesystem option maxSize must be unlimited", Long.MAX_VALUE, maxFilesystemSize);
146 
147         // Small FS
148         final FileObject fo3 = manager.resolveFile("ram:/fo3", smallSizedFso);
149         final FileObject fo4 = manager.resolveFile("ram:/", smallSizedFso);
150         assertSame("Both files should exist in the same FileSystem instance.", fo3.getFileSystem(), fo4.getFileSystem());
151         assertNotSame("Both files should exist in different FileSystem instance.", fo1.getFileSystem(), fo3.getFileSystem());
152 
153         fsOptions = fo3.getFileSystem().getFileSystemOptions();
154         maxFilesystemSize = RamFileSystemConfigBuilder.getInstance().getLongMaxSize(fsOptions);
155         assertEquals("Filesystem option maxSize must be set", 10, maxFilesystemSize);
156     }
157 
158     /**
159      * Tests VFS-625.
160      * @throws FileSystemException
161      */
162     @Test
163     public void testMoveFile() throws FileSystemException {
164         final FileObject fileSource = manager.resolveFile("ram://virtual/source");
165         fileSource.createFile();
166         final FileObject fileDest = manager.resolveFile("ram://virtual/dest");
167         Assert.assertTrue(fileSource.canRenameTo(fileDest));
168         fileSource.moveTo(fileDest);
169     }
170 
171     @Test
172     public void testReadEmptyFileByteByByte() throws FileSystemException, IOException {
173         final InputStream input = this.createEmptyFile();
174         assertEquals("Empty file didnt return EOF -1", -1, input.read());
175     }
176 
177     @Test
178     public void testReadEmptyFileIntoBuffer() throws FileSystemException, IOException {
179         final InputStream input = this.createEmptyFile();
180 
181         final byte[] buffer = new byte[100];
182         assertEquals("Empty file didnt return when filling buffer", -1, input.read(buffer));
183         assertArrayEquals("Buffer was written too", new byte[100], buffer);
184     }
185 
186     @Test
187     public void testReadEmptyFileIntoBufferWithOffsetAndLength() throws FileSystemException, IOException {
188         final InputStream input = this.createEmptyFile();
189         final byte[] buffer = new byte[100];
190         assertEquals("Empty file didnt return when filling buffer", -1, input.read(buffer, 10, 90));
191         assertArrayEquals("Buffer was written too", new byte[100], buffer);
192     }
193 
194     @Test
195     public void testReadNonEmptyFileByteByByte() throws FileSystemException, IOException {
196         final InputStream input = this.createNonEmptyFile();
197 
198         assertEquals("Read 1st byte failed", 1, input.read());
199         assertEquals("Rread 2st byte failed", 2, input.read());
200         assertEquals("Read 3st byte failed", 3, input.read());
201         assertEquals("File should be empty", -1, input.read());
202     }
203 
204     @Test
205     public void testReadNonEmptyFileIntoBuffer() throws FileSystemException, IOException {
206         final InputStream input = this.createNonEmptyFile();
207 
208         final byte[] buffer = new byte[100];
209         assertEquals("Filling buffer failed when file is not empty", NON_EMPTY_FILE_CONTENT.length, input.read(buffer));
210 
211         final byte[] expectedBuffer = new byte[100];
212         System.arraycopy(NON_EMPTY_FILE_CONTENT, 0, expectedBuffer, 0, NON_EMPTY_FILE_CONTENT.length);
213         assertArrayEquals("Buffer not filled", expectedBuffer, buffer);
214 
215         Arrays.fill(buffer, (byte) 0);
216         Arrays.fill(expectedBuffer, (byte) 0);
217 
218         assertEquals("File should be empty after filling buffer", -1, input.read(buffer));
219         assertArrayEquals("Buffer was written when empty", expectedBuffer, buffer);
220     }
221 
222     @Test
223     public void testReadNonEmptyFileIntoBufferWithOffsetAndLength() throws FileSystemException, IOException {
224         final InputStream input = this.createNonEmptyFile();
225 
226         final byte[] buffer = new byte[100];
227         final int offset = 10;
228         assertEquals("Filling buffer failed when file is not empty", NON_EMPTY_FILE_CONTENT.length,
229                 input.read(buffer, offset, 100 - offset));
230 
231         final byte[] expectedBuffer = new byte[100];
232         System.arraycopy(NON_EMPTY_FILE_CONTENT, 0, expectedBuffer, offset, NON_EMPTY_FILE_CONTENT.length);
233         assertArrayEquals("Buffer not filled", expectedBuffer, buffer);
234 
235         Arrays.fill(buffer, (byte) 0);
236         Arrays.fill(expectedBuffer, (byte) 0);
237         assertEquals("File should be empty after filling buffer", -1, input.read(buffer, 10, 90));
238         assertArrayEquals("Buffer was written when empty", expectedBuffer, buffer);
239     }
240 
241     /**
242      *
243      * Checks root folder exists
244      *
245      * @throws FileSystemException
246      */
247     @Test
248     public void testRootFolderExists() throws FileSystemException {
249         final FileObject root = manager.resolveFile("ram:///", defaultRamFso);
250         assertTrue(root.getType().hasChildren());
251 
252         try {
253             root.delete();
254             fail();
255         } catch (final FileSystemException e) {
256             // Expected
257         }
258 
259     }
260 
261     /**
262      * Test if listing files with known scheme prefix works.
263      * <p>
264      * This test is not RamProvider specific but it uses it as a simple test-bed.
265      * Verifies VFS-741.
266      */
267     @Test
268     public void testSchemePrefix() throws FileSystemException
269     {
270         // use a :-prefix with a known scheme (unknown scheme works since VFS-398)
271         final String KNOWN_SCHEME = manager.getSchemes()[0]; // typically "ram"
272 
273         // we test with this file name
274         final String testDir = "/prefixtest/";
275         final String testFileName = KNOWN_SCHEME + ":test:txt";
276         final String expectedName = testDir + testFileName;
277 
278         final FileObject dir = prepareSpecialFile(testDir, testFileName);
279 
280 
281         // verify we can list dir
282 
283         // if not it throws:
284         // Caused by: org.apache.commons.vfs2.FileSystemException: Invalid descendent file name "ram:data:test.txt".
285         //   at org.apache.commons.vfs2.impl.DefaultFileSystemManager.resolveName
286         //   at org.apache.commons.vfs2.provider.AbstractFileObject.getChildren
287         //   at org.apache.commons.vfs2.provider.AbstractFileObject.traverse
288         //   at org.apache.commons.vfs2.provider.AbstractFileObject.findFiles
289 
290         // test methods to get the child:
291         final FileObject[] findFilesResult = dir.findFiles(new AllFileSelector()); // includes dir
292         final FileObject[] getChildrenResult = dir.getChildren();
293         final FileObject getChildResult = dir.getChild(testFileName);
294 
295         // validate findFiles returns expected result
296         assertEquals("Unexpected result findFiles: " + Arrays.toString(findFilesResult), 2, findFilesResult.length);
297         String resultName = findFilesResult[0].getName().getPathDecoded();
298         assertEquals("findFiles Child name does not match", expectedName, resultName);
299         assertEquals("Did findFiles but child was no file", FileType.FILE, findFilesResult[0].getType());
300 
301         // validate getChildren returns expected result
302         assertEquals("Unexpected result getChildren: " + Arrays.toString(getChildrenResult), 1, getChildrenResult.length);
303         resultName = getChildrenResult[0].getName().getPathDecoded();
304         assertEquals("getChildren Child name does not match", expectedName, resultName);
305         assertEquals("Did getChildren but child was no file", FileType.FILE, getChildrenResult[0].getType());
306 
307         // validate getChild returns expected child
308         assertNotNull("Did not find direct child", getChildResult);
309         resultName = getChildResult.getName().getPathDecoded();
310         assertEquals("getChild name does not match", expectedName, resultName);
311         assertEquals("getChild was no file", FileType.FILE, getChildResult.getType());
312     }
313 
314     @Test
315     public void testSmallFS() throws Exception {
316         // Small FS
317         final FileObject fo3 = manager.resolveFile("ram:/fo3", smallSizedFso);
318         fo3.createFile();
319         try {
320             final OutputStream os = fo3.getContent().getOutputStream();
321             os.write(new byte[10]);
322             os.close();
323         } catch (final FileSystemException e) {
324             fail("Test should be able to save such a small file");
325         }
326 
327         try {
328             final OutputStream os = fo3.getContent().getOutputStream();
329             os.write(new byte[11]);
330             os.close();
331             fail("It shouldn't save such a big file");
332         } catch (final FileSystemException e) {
333             // Expected
334         }
335     }
336 
337 
338     /**
339      * Test some special file name symbols.
340      * <p>
341      * Use the RamProvider since it has no character limitations like
342      * the (Windows) LocalFileProvider.
343      */
344     @Test
345     public void testSpecialName() throws FileSystemException
346     {
347         // we test with this file name
348         // does not work with '!'
349         final String testDir = "/spacialtest/";
350         final String testFileName = "test:+-_ \"()<>%#.txt";
351         final String expectedName = testDir + testFileName;
352 
353         final FileObject dir = prepareSpecialFile(testDir, testFileName);
354 
355 
356         // DO: verify you can list it:
357         final FileObject[] findFilesResult = dir.findFiles(new AllFileSelector()); // includes dir
358         final FileObject[] getChildrenResult = dir.getChildren();
359         final FileObject getChildResult = dir.getChild(UriParser.encode(testFileName, ENC));
360 
361 
362         // validate findFiles returns expected result
363         assertEquals("Unexpected result findFiles: " + Arrays.toString(findFilesResult), 2, findFilesResult.length);
364         String resultName = findFilesResult[0].getName().getPathDecoded();
365         assertEquals("findFiles Child name does not match", expectedName, resultName);
366         assertEquals("Did findFiles but child was no file", FileType.FILE, findFilesResult[0].getType());
367 
368         // validate getChildren returns expected result
369         assertEquals("Unexpected result getChildren: " + Arrays.toString(getChildrenResult), 1, getChildrenResult.length);
370         resultName = getChildrenResult[0].getName().getPathDecoded();
371         assertEquals("getChildren Child name does not match", expectedName, resultName);
372         assertEquals("Did getChildren but child was no file", FileType.FILE, getChildrenResult[0].getType());
373 
374         // validate getChild returns expected child
375         assertNotNull("Did not find direct child", getChildResult);
376         resultName = getChildResult.getName().getPathDecoded();
377         assertEquals("getChild name does not match", expectedName, resultName);
378         assertEquals("getChild was no file", FileType.FILE, getChildResult.getType());
379     }
380 }