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