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