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;
18  
19  import static org.junit.Assert.assertArrayEquals;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.InputStream;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.net.URLConnection;
26  import java.nio.charset.StandardCharsets;
27  
28  import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
29  import org.apache.commons.vfs2.provider.AbstractFileSystem;
30  import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider;
31  import org.junit.Assert;
32  
33  import junit.framework.Test;
34  import junit.framework.TestCase;
35  
36  /**
37   * File system test cases, which verifies the structure and naming functionality.
38   * <p>
39   * Works from a base folder, and assumes a particular structure under that base folder.
40   */
41  public abstract class AbstractProviderTestCase extends AbstractVfsTestCase {
42      // Expected contents of "file1.txt"
43      public static final String FILE1_CONTENT = "This is a test file.";
44      // Expected contents of test files
45      public static final String TEST_FILE_CONTENT = "A test file.";
46      protected static Test notConfigured(final Class<?> testClass) {
47          return warning(testClass + " is not configured for tests, skipping");
48      }
49      private static Test warning(final String message) {
50          return new TestCase("warning") {
51              @Override
52              protected void runTest() {
53                  System.out.println(message);
54              }
55          };
56      }
57      private FileObject baseFolder;
58      private FileObject readFolder;
59      private FileObject writeFolder;
60  
61      private DefaultFileSystemManager manager;
62  
63      private ProviderTestConfig providerConfig;
64  
65      private Method method;
66  
67      private boolean addEmptyDir;
68  
69      protected void addEmptyDir(final boolean addEmptyDir) {
70          this.addEmptyDir = addEmptyDir;
71      }
72  
73      /**
74       * Asserts that the content of a file is the same as expected. Checks the length reported by getSize() is correct,
75       * then reads the content as a byte stream and compares the result with the expected content. Assumes files are
76       * encoded using UTF-8.
77       */
78      protected void assertSameContent(final String expected, final FileObject file) throws Exception {
79          // Check the file exists, and is a file
80          assertTrue(file.exists());
81          assertSame(FileType.FILE, file.getType());
82          assertTrue(file.isFile());
83  
84          // Get file content as a binary stream
85          final byte[] expectedBin = expected.getBytes(StandardCharsets.UTF_8);
86  
87          // Check lengths
88          final FileContent content = file.getContent();
89          assertEquals("same content length", expectedBin.length, content.getSize());
90  
91          // Read content into byte array
92          final InputStream instr = content.getInputStream();
93          final ByteArrayOutputStream outstr;
94          try {
95              outstr = new ByteArrayOutputStream(expectedBin.length);
96              final byte[] buffer = new byte[256];
97              int nread = 0;
98              while (nread >= 0) {
99                  outstr.write(buffer, 0, nread);
100                 nread = instr.read(buffer);
101             }
102         } finally {
103             instr.close();
104         }
105 
106         // Compare
107         assertArrayEquals("same binary content", expectedBin, outstr.toByteArray());
108     }
109 
110     /**
111      * Asserts that the content of a file is the same as expected. Checks the length reported by getContentLength() is
112      * correct, then reads the content as a byte stream and compares the result with the expected content. Assumes files
113      * are encoded using UTF-8.
114      */
115     protected void assertSameURLContent(final String expected, final URLConnection connection) throws Exception {
116         // Get file content as a binary stream
117         final byte[] expectedBin = expected.getBytes(StandardCharsets.UTF_8);
118 
119         // Check lengths
120         assertEquals("same content length", expectedBin.length, connection.getContentLength());
121 
122         // Read content into byte array
123         final InputStream instr = connection.getInputStream();
124         final ByteArrayOutputStream outstr;
125         try {
126             outstr = new ByteArrayOutputStream();
127             final byte[] buffer = new byte[256];
128             int nread = 0;
129             while (nread >= 0) {
130                 outstr.write(buffer, 0, nread);
131                 nread = instr.read(buffer);
132             }
133         } finally {
134             instr.close();
135         }
136 
137         // Compare
138         assertArrayEquals("same binary content", expectedBin, outstr.toByteArray());
139     }
140 
141     /**
142      * Builds the expected structure of the read tests folder.
143      *
144      * @throws FileSystemException (possibly)
145      */
146     protected FileInfo buildExpectedStructure() throws FileSystemException {
147         // Build the expected structure
148         final FileInfoInfo.html#FileInfo">FileInfo base = new FileInfo(getReadFolder().getName().getBaseName(), FileType.FOLDER);
149         base.addFile("file1.txt", FILE1_CONTENT);
150         // file%.txt - test out encoding
151         base.addFile("file%25.txt", FILE1_CONTENT);
152 
153         // file?test.txt - test out encoding (test.txt is not the queryString)
154         // as we do not know if the current file provider we need to
155         // ask it to normalize the name
156         // todo: move this into the FileInfo class to do it generally?
157         /*
158          * webdav-bug?: didnt manage to get the "?" correctly through webdavlib FileSystemManager fsm =
159          * getReadFolder().getFileSystem().getFileSystemManager(); FileName fn =
160          * fsm.resolveName(getReadFolder().getName(), "file%3ftest.txt"); String baseName = fn.getBaseName();
161          * base.addFile(baseName, FILE1_CONTENT);
162          */
163         base.addFile("file space.txt", FILE1_CONTENT);
164 
165         base.addFile("empty.txt", "");
166         if (addEmptyDir) {
167             base.addFolder("emptydir");
168         }
169 
170         final FileInfo dir = base.addFolder("dir1");
171         dir.addFile("file1.txt", TEST_FILE_CONTENT);
172         dir.addFile("file2.txt", TEST_FILE_CONTENT);
173         dir.addFile("file3.txt", TEST_FILE_CONTENT);
174 
175         final FileInfo subdir1 = dir.addFolder("subdir1");
176         subdir1.addFile("file1.txt", TEST_FILE_CONTENT);
177         subdir1.addFile("file2.txt", TEST_FILE_CONTENT);
178         subdir1.addFile("file3.txt", TEST_FILE_CONTENT);
179 
180         final FileInfo subdir2 = dir.addFolder("subdir2");
181         subdir2.addFile("file1.txt", TEST_FILE_CONTENT);
182         subdir2.addFile("file2.txt", TEST_FILE_CONTENT);
183         subdir2.addFile("file3.txt", TEST_FILE_CONTENT);
184 
185         final FileInfo subdir3 = dir.addFolder("subdir3");
186         subdir3.addFile("file1.txt", TEST_FILE_CONTENT);
187         subdir3.addFile("file2.txt", TEST_FILE_CONTENT);
188         subdir3.addFile("file3.txt", TEST_FILE_CONTENT);
189 
190         final FileInfo subdir4 = dir.addFolder("subdir4.jar");
191         subdir4.addFile("file1.txt", TEST_FILE_CONTENT);
192         subdir4.addFile("file2.txt", TEST_FILE_CONTENT);
193         subdir4.addFile("file3.txt", TEST_FILE_CONTENT);
194 
195         return base;
196     }
197 
198     /**
199      * creates a new uninitialized file system manager
200      *
201      * @throws Exception
202      */
203     protected DefaultFileSystemManager createManager() throws Exception {
204         final DefaultFileSystemManager fs = getProviderConfig().getDefaultFileSystemManager();
205         fs.setFilesCache(getProviderConfig().getFilesCache());
206         getProviderConfig().prepare(fs);
207         if (!fs.hasProvider("file")) {
208             fs.addProvider("file", new DefaultLocalFileProvider());
209         }
210         return fs;
211     }
212 
213     /**
214      * Returns the base test folder. This is the parent of both the read test and write test folders.
215      */
216     public FileObject getBaseFolder() {
217         return baseFolder;
218     }
219 
220     /**
221      * some provider config do some post-initialization in getBaseTestFolder. This is a hack to allow access to this
222      * code for {@code createManager}
223      */
224     public FileObject getBaseTestFolder(final FileSystemManager fs) throws Exception {
225         return providerConfig.getBaseTestFolder(fs);
226     }
227 
228     protected FileSystem getFileSystem() {
229         final FileObject rFolder = getReadFolder();
230         Assert.assertNotNull("This test's read folder should not be null", rFolder);
231         return rFolder.getFileSystem();
232     }
233 
234     /**
235      * Returns the file system manager used by this test.
236      */
237     protected DefaultFileSystemManager getManager() {
238         return manager;
239     }
240 
241     /**
242      * get the provider configuration
243      */
244     public ProviderTestConfig getProviderConfig() {
245         return providerConfig;
246     }
247 
248     /**
249      * Returns the read test folder.
250      */
251     protected FileObject getReadFolder() {
252         return readFolder;
253     }
254 
255     /**
256      * Returns the capabilities required by the tests of this test case. The tests are not run if the provider being
257      * tested does not support all the required capabilities. Return null or an empty array to always run the tests.
258      * <p>
259      * This implementation returns null.
260      */
261     protected Capability[] getRequiredCapabilities() {
262         return null;
263     }
264 
265     /**
266      * Returns the write test folder.
267      */
268     protected FileObject getWriteFolder() {
269         return writeFolder;
270     }
271 
272     /**
273      * Runs the test. This implementation short-circuits the test if the provider being tested does not have the
274      * capabilities required by this test.
275      * <p>
276      * TODO - Handle negative caps as well - ie, only run a test if the provider does not have certain caps.
277      * </p>
278      * <p>
279      * TODO - Figure out how to remove the test from the TestResult if the test is skipped.
280      * </p>
281      */
282     @Override
283     protected void runTest() throws Throwable {
284         // Check the capabilities
285         final Capability[] caps = getRequiredCapabilities();
286         if (caps != null) {
287             for (final Capability cap2 : caps) {
288                 final Capability cap = cap2;
289                 final FileSystem fs = getFileSystem();
290                 if (!fs.hasCapability(cap)) {
291                     // String name = fs.getClass().getName();
292                     // int index = name.lastIndexOf('.');
293                     // String fsName = (index > 0) ? name.substring(index + 1) : name;
294                     // System.out.println("skipping " + getName() + " because " +
295                     // fsName + " does not have capability " + cap);
296                     return;
297                 }
298             }
299         }
300 
301         // Provider has all the capabilities - execute the test
302         if (method != null) {
303             try {
304                 method.invoke(this, (Object[]) null);
305             } catch (final InvocationTargetException e) {
306                 throw e.getTargetException();
307             }
308         } else {
309             super.runTest();
310         }
311 
312         if (readFolder != null && ((AbstractFileSystem) readFolder.getFileSystem()).isOpen()) {
313             String name = "unknown";
314             if (method != null) {
315                 name = method.getName();
316             }
317 
318             throw new IllegalStateException(getClass().getName() + ": filesystem has open streams after: " + name);
319         }
320     }
321 
322     /**
323      * Configures this test.
324      */
325     public void setConfig(final DefaultFileSystemManager manager, final ProviderTestConfig providerConfig,
326             final FileObject baseFolder, final FileObject readFolder, final FileObject writeFolder) {
327         this.manager = manager;
328         this.providerConfig = providerConfig;
329         this.baseFolder = baseFolder;
330         this.readFolder = readFolder;
331         this.writeFolder = writeFolder;
332         assertNotNull("setConfig manager", manager);
333         assertNotNull("setConfig providerConfig", providerConfig);
334         assertNotNull("setConfig baseFolder", baseFolder);
335         assertNotNull("setConfig readFolder", readFolder);
336         assertNotNull("setConfig writeFolder", writeFolder);
337     }
338 
339     /**
340      * Sets the test method.
341      */
342     public void setMethod(final Method method) {
343         this.method = method;
344     }
345 
346     /**
347      * Sets the write test folder.
348      *
349      * @param folder
350      */
351     protected void setWriteFolder(final FileObject folder) {
352         writeFolder = folder;
353     }
354 
355     @Override
356     public String toString() {
357         return "AbstractProviderTestCase [baseFolder=" + baseFolder + ", readFolder=" + readFolder + ", writeFolder="
358                 + writeFolder + ", manager=" + manager + ", providerConfig=" + providerConfig + ", method=" + method
359                 + ", addEmptyDir=" + addEmptyDir + "]";
360     }
361 }