View Javadoc

1   package org.apache.maven.shared.utils.io;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.shared.utils.testhelpers.FileTestHelper;
23  import org.junit.Ignore;
24  import org.junit.Rule;
25  import org.junit.Test;
26  import org.junit.Assert;
27  import org.junit.rules.TemporaryFolder;
28  
29  import java.io.File;
30  import java.io.IOException;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.List;
34  
35  public class DirectoryScannerTest
36  {
37      private static final String[] NONE = new String[0];
38  
39      @Rule
40      public TemporaryFolder tempFolder = new TemporaryFolder();
41  
42      private void createTestData()
43          throws IOException
44      {
45          File rootDir = tempFolder.getRoot();
46          File folder1 = new File( rootDir, "folder1" );
47          folder1.mkdirs();
48  
49          FileTestHelper.generateTestFile( new File( rootDir, "file1.txt" ), 11 );
50          FileTestHelper.generateTestFile( new File( rootDir, "file2.txt" ), 12 );
51          FileTestHelper.generateTestFile( new File( rootDir, "file3.dat" ), 13 );
52  
53          FileTestHelper.generateTestFile( new File( folder1, "file4.txt" ), 14 );
54          FileTestHelper.generateTestFile( new File( folder1, "file5.dat" ), 15 );
55  
56          File folder2 = new File( folder1, "ignorefolder" );
57          folder2.mkdirs();
58          FileTestHelper.generateTestFile( new File( folder2, "file7.txt" ), 17 );
59      }
60  
61      @Test
62      public void testSimpleScan()
63          throws Exception
64      {
65          createTestData();
66  
67          fitScanTest( true, true, true,
68                  /* includes */        null,
69                  /* excludes */        null,
70                  /* expInclFiles */    new String[]{ "file1.txt", "file2.txt", "file3.dat", "folder1/file4.txt", "folder1/file5.dat" },
71                  /* expInclDirs */     new String[]{ "", "folder1" },
72                  /* expNotInclFiles */ NONE,
73                  /* expNotInclDirs  */ NONE,
74                  /* expNotExclFiles */ NONE,
75                  /* expNotExclDirs  */ NONE );
76  
77          // same without followSymlinks
78          fitScanTest( true, false, true,
79                  /* includes */        null,
80                  /* excludes */        null,
81                  /* expInclFiles */    new String[]{ "file1.txt", "file2.txt", "file3.dat", "folder1/file4.txt", "folder1/file5.dat" },
82                  /* expInclDirs */     new String[]{ "", "folder1" },
83                  /* expNotInclFiles */ NONE,
84                  /* expNotInclDirs  */ NONE,
85                  /* expNotExclFiles */ NONE,
86                  /* expNotExclDirs  */ NONE );
87      }
88  
89      @Test
90      public void testSimpleIncludes()
91          throws Exception
92      {
93          createTestData();
94  
95          fitScanTest( true, true, true,
96                  /* includes        */ new String[]{ "**/*.dat", "*.somethingelse" },
97                  /* excludes        */ null,
98                  /* expInclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
99                  /* expInclDirs     */ NONE,
100                 /* expNotInclFiles */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
101                 /* expNotInclDirs  */ new String[]{ "", "folder1" },
102                 /* expExclFiles    */ NONE,
103                 /* expExclDirs     */ NONE );
104 
105         // same without followSymlinks
106         fitScanTest( true, false, true,
107                 /* includes        */ new String[]{ "**/*.dat", "*.somethingelse" },
108                 /* excludes        */ null,
109                 /* expInclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
110                 /* expInclDirs     */ NONE,
111                 /* expNotInclFiles */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
112                 /* expNotInclDirs  */ new String[]{ "", "folder1" },
113                 /* expExclFiles    */ NONE,
114                 /* expExclDirs     */ NONE );
115     }
116 
117     @Test
118     public void testSimpleExcludes()
119         throws Exception
120     {
121         createTestData();
122 
123         fitScanTest( true, true, true,
124                 /* includes        */ null,
125                 /* excludes        */ new String[]{ "**/*.dat", "*.somethingelse" },
126                 /* expInclFiles    */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
127                 /* expInclDirs     */ new String[]{ "", "folder1" },
128                 /* expNotInclFiles */ NONE,
129                 /* expNotInclDirs  */ NONE,
130                 /* expExclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
131                 /* expExclDirs     */ NONE );
132 
133         // same without followSymlinks
134         fitScanTest( true, false, true,
135                 /* includes        */ null,
136                 /* excludes        */ new String[]{ "**/*.dat", "*.somethingelse" },
137                 /* expInclFiles    */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
138                 /* expInclDirs     */ new String[]{ "", "folder1" },
139                 /* expNotInclFiles */ NONE,
140                 /* expNotInclDirs  */ NONE,
141                 /* expExclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
142                 /* expExclDirs     */ NONE );
143     }
144 
145     public void testIsSymLin()
146         throws IOException
147     {
148         File file = new File( "." );
149         DirectoryScanner ds = new DirectoryScanner();
150         ds.isSymbolicLink( file, "abc" );
151     }
152 
153     /**
154      * Performs a scan and test for the given parameters if not null.
155      */
156     private void fitScanTest( boolean caseSensitive,
157                               boolean followSymLinks,
158                               boolean addDefaultExcludes,
159                               String[] includes, String[] excludes,
160                               String[] expectedIncludedFiles,
161                               String[] expectedIncludedDirectories,
162                               String[] expectedNotIncludedFiles,
163                               String[] expectedNotIncludedDirectories,
164                               String[] expectedExcludedFiles,
165                               String[] expectedExcludedDirectories )
166     {
167         DirectoryScanner ds = new DirectoryScanner();
168         ds.setBasedir( tempFolder.getRoot() );
169 
170         ds.setCaseSensitive( caseSensitive );
171         ds.setFollowSymlinks( followSymLinks );
172 
173         if ( addDefaultExcludes )
174         {
175             ds.addDefaultExcludes();
176         }
177         if ( includes != null )
178         {
179             ds.setIncludes( includes );
180         }
181         if ( excludes != null )
182         {
183             ds.setExcludes( excludes );
184         }
185 
186         TestScanConductor scanConductor =  new TestScanConductor();
187 
188         ds.setScanConductor( scanConductor );
189 
190         ds.scan();
191 
192         checkFiles( "expectedIncludedFiles", expectedIncludedFiles, ds.getIncludedFiles() );
193         checkFiles( "expectedIncludedDirectories", expectedIncludedDirectories, ds.getIncludedDirectories() );
194         checkFiles( "expectedNotIncludedFiles", expectedNotIncludedFiles, ds.getNotIncludedFiles() );
195         checkFiles( "expectedNotIncludedDirectories", expectedNotIncludedDirectories, ds.getNotIncludedDirectories() );
196         checkFiles( "expectedExcludedFiles", expectedExcludedFiles, ds.getExcludedFiles() );
197         checkFiles( "expectedExcludedDirectories", expectedExcludedDirectories, ds.getExcludedDirectories() );
198 
199         checkFiles( "visitedFiles", expectedIncludedFiles,
200                     scanConductor.visitedFiles.toArray( new String[scanConductor.visitedFiles.size()] ) );
201     }
202 
203     /**
204      * Check if the resolved files match the rules of the expected files.
205      * @param expectedFiles
206      * @param resolvedFiles
207      */
208     private void checkFiles( String category, String[] expectedFiles, String[] resolvedFiles )
209     {
210         if ( expectedFiles != null )
211         {
212             String msg = category + " expected: " + Arrays.toString( expectedFiles ) + " but got: " + Arrays.toString( resolvedFiles );
213             Assert.assertNotNull( msg, resolvedFiles );
214             Assert.assertEquals( msg, expectedFiles.length, resolvedFiles.length );
215 
216             Arrays.sort( expectedFiles );
217             Arrays.sort( resolvedFiles );
218 
219             for ( int i = 0; i < resolvedFiles.length; i++ )
220             {
221                 Assert.assertEquals( msg, expectedFiles[i], resolvedFiles[i].replace( "\\", "/" ) );
222             }
223         }
224     }
225 
226     private static class TestScanConductor
227         implements ScanConductor
228     {
229         final List<String> visitedFiles = new ArrayList<String>();
230 
231         public ScanConductor.ScanAction visitDirectory( String name, File directory )
232         {
233             Assert.assertTrue( directory.isDirectory() );
234 
235             if ( directory.getName().equals( "ignorefolder" ) )
236             {
237                 return ScanAction.NO_RECURSE;
238             }
239 
240             return ScanAction.CONTINUE;
241         }
242 
243         public ScanConductor.ScanAction visitFile( String name, File file )
244         {
245             Assert.assertTrue( file.isFile() );
246             visitedFiles.add( name );
247             return ScanAction.CONTINUE;
248         }
249     }
250 
251     private void removeAndAddSomeFiles()
252         throws IOException
253     {
254         File rootDir = tempFolder.getRoot();
255         File file2 = new File( rootDir, "file2.txt" );
256         file2.delete();
257 
258         FileTestHelper.generateTestFile( new File( rootDir, "folder1/file9.txt" ), 15 );
259 
260         File folder2 = new File( rootDir, "folder1/ignorefolder" );
261         FileUtils.deleteDirectory( folder2 );
262     }
263 
264     @Test
265     public void testScanDiff()
266         throws Exception
267     {
268         createTestData();
269 
270         DirectoryScanner dss = new DirectoryScanner();
271         dss.setBasedir( tempFolder.getRoot() );
272         Assert.assertNotNull( dss );
273 
274         // we take the initial snapshot
275         dss.scan();
276         String[] oldFiles = dss.getIncludedFiles();
277 
278         // now we change 3 files. add one and remove
279         removeAndAddSomeFiles();
280 
281         dss.scan();
282 
283         DirectoryScanResult dsr = dss.diffIncludedFiles( oldFiles );
284 
285         String[] addedFiles = dsr.getFilesAdded();
286         String[] removedFiles = dsr.getFilesRemoved();
287         Assert.assertNotNull( addedFiles );
288         Assert.assertNotNull( removedFiles );
289         Assert.assertEquals( 1, addedFiles.length );
290         Assert.assertEquals( 2, removedFiles.length );
291     }
292 
293     @Ignore("Enable this test to run performance checks")
294     @Test
295     public void performanceTest()
296         throws Exception
297     {
298 
299         File rootFolder = tempFolder.getRoot();
300 
301         // do some warmup
302         for ( int i = 1; i < 200; i++ )
303         {
304             createTestData();
305             removeAndAddSomeFiles();
306             FileUtils.deleteDirectory( rootFolder );
307         }
308 
309         int cycles = 2000;
310 
311         // and now we take the time _without_
312         long startTime = System.nanoTime();
313         for ( int i = 1; i < cycles; i++ )
314         {
315             createTestData();
316             removeAndAddSomeFiles();
317             FileUtils.deleteDirectory( rootFolder );
318             rootFolder.mkdir();
319         }
320         long endTime = System.nanoTime();
321 
322         long durationEmptyRun = endTime - startTime;
323         System.out.println( "durationEmptyRun            [ns]: " + durationEmptyRun );
324 
325         startTime = System.nanoTime();
326         for ( int i = 1; i < cycles; i++ )
327         {
328             createTestData();
329             DirectoryScanner directoryScanner = new DirectoryScanner();
330             directoryScanner.setBasedir( rootFolder );
331             directoryScanner.scan();
332             String[] oldFiles = directoryScanner.getIncludedFiles();
333 
334             removeAndAddSomeFiles();
335 
336             directoryScanner.scan();
337 
338             DirectoryScanResult directoryScanResult = directoryScanner.diffIncludedFiles( oldFiles );
339             Assert.assertNotNull( directoryScanResult );
340 
341             FileUtils.deleteDirectory( rootFolder );
342             rootFolder.mkdir();
343         }
344         endTime = System.nanoTime();
345 
346         long durationWithSnapshotScanner = endTime - startTime;
347         System.out.println( "durationWithSnapshotScanner [ns]: " + durationWithSnapshotScanner );
348 
349         long dirScannerOverhead = durationWithSnapshotScanner - durationEmptyRun;
350 
351         System.out.println( "Overhead for n cycles [ns]: " + dirScannerOverhead );
352     }
353 
354 }