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.Assert;
24  import org.junit.Ignore;
25  import org.junit.Rule;
26  import org.junit.Test;
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  import static org.junit.Assert.assertEquals;
36  import static org.junit.Assert.assertTrue;
37  
38  public class DirectoryScannerTest
39  {
40      private static final String[] NONE = new String[0];
41  
42      @Rule
43      public TemporaryFolder tempFolder = new TemporaryFolder();
44  
45      private void createTestData()
46          throws IOException
47      {
48          File rootDir = tempFolder.getRoot();
49          File folder1 = new File( rootDir, "folder1" );
50          folder1.mkdirs();
51  
52          FileTestHelper.generateTestFile( new File( rootDir, "file1.txt" ), 11 );
53          FileTestHelper.generateTestFile( new File( rootDir, "file2.txt" ), 12 );
54          FileTestHelper.generateTestFile( new File( rootDir, "file3.dat" ), 13 );
55  
56          FileTestHelper.generateTestFile( new File( folder1, "file4.txt" ), 14 );
57          FileTestHelper.generateTestFile( new File( folder1, "file5.dat" ), 15 );
58  
59          File folder2 = new File( folder1, "ignorefolder" );
60          folder2.mkdirs();
61          FileTestHelper.generateTestFile( new File( folder2, "file7.txt" ), 17 );
62      }
63  
64      @Test
65      public void testSimpleScan()
66          throws Exception
67      {
68          createTestData();
69  
70          fitScanTest( true, true, true,
71                  /* includes */        null,
72                  /* excludes */        null,
73                  /* expInclFiles */
74                  new String[]{ "file1.txt", "file2.txt", "file3.dat", "folder1/file4.txt", "folder1/file5.dat" },
75                  /* expInclDirs */     new String[]{ "", "folder1" },
76                  /* expNotInclFiles */ NONE,
77                  /* expNotInclDirs  */ NONE,
78                  /* expNotExclFiles */ NONE,
79                  /* expNotExclDirs  */ NONE );
80  
81          // same without followSymlinks
82          fitScanTest( true, false, true,
83                  /* includes */        null,
84                  /* excludes */        null,
85                  /* expInclFiles */
86                  new String[]{ "file1.txt", "file2.txt", "file3.dat", "folder1/file4.txt", "folder1/file5.dat" },
87                  /* expInclDirs */     new String[]{ "", "folder1" },
88                  /* expNotInclFiles */ NONE,
89                  /* expNotInclDirs  */ NONE,
90                  /* expNotExclFiles */ NONE,
91                  /* expNotExclDirs  */ NONE );
92      }
93  
94      @Test
95      public void testSimpleIncludes()
96          throws Exception
97      {
98          createTestData();
99  
100         fitScanTest( true, true, true,
101                 /* includes        */ new String[]{ "**/*.dat", "*.somethingelse" },
102                 /* excludes        */ null,
103                 /* expInclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
104                 /* expInclDirs     */ NONE,
105                 /* expNotInclFiles */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
106                 /* expNotInclDirs  */ new String[]{ "", "folder1" },
107                 /* expExclFiles    */ NONE,
108                 /* expExclDirs     */ NONE );
109 
110         // same without followSymlinks
111         fitScanTest( true, false, true,
112                 /* includes        */ new String[]{ "**/*.dat", "*.somethingelse" },
113                 /* excludes        */ null,
114                 /* expInclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
115                 /* expInclDirs     */ NONE,
116                 /* expNotInclFiles */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
117                 /* expNotInclDirs  */ new String[]{ "", "folder1" },
118                 /* expExclFiles    */ NONE,
119                 /* expExclDirs     */ NONE );
120     }
121 
122     @Test
123     public void checkSymlinkBehaviour(){
124         DirectoryScanner ds = new DirectoryScanner();
125         ds.setBasedir( new File("src/test/resources/symlinks/src") );
126         ds.setFollowSymlinks( false );
127         ds.scan();
128         String[] includedDirectories = ds.getIncludedDirectories();
129         String[] files = ds.getIncludedFiles();
130         System.out.println( "files = " + files );
131 
132 
133     }
134 
135     @Test
136     @Ignore("Wait until we can run with assembly 2.5 which will support symlinks properly")
137     public void followSymlinksFalse()
138     {
139         if (!Java7Support.isAtLeastJava7()) return;
140         DirectoryScanner ds = new DirectoryScanner();
141         ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) );
142         ds.setFollowSymlinks( false );
143         ds.scan();
144         List<String> included = Arrays.asList( ds.getIncludedFiles() );
145         assertAlwaysIncluded( included );
146         assertEquals( 9, included.size() );
147         List<String> includedDirs = Arrays.asList( ds.getIncludedDirectories() );
148         assertTrue( includedDirs.contains( "" ) ); // w00t !
149         assertTrue( includedDirs.contains( "aRegularDir" ) );
150         assertTrue( includedDirs.contains( "symDir" ) );
151         assertTrue( includedDirs.contains( "symLinkToDirOnTheOutside" ) );
152         assertTrue( includedDirs.contains( "targetDir" ) );
153         assertEquals( 5, includedDirs.size() );
154     }
155 
156     private void assertAlwaysIncluded( List<String> included )
157     {
158         assertTrue( included.contains( "aRegularDir/aRegularFile.txt" ) );
159         assertTrue( included.contains( "targetDir/targetFile.txt" ) );
160         assertTrue( included.contains( "fileR.txt" ) );
161         assertTrue( included.contains( "fileW.txt" ) );
162         assertTrue( included.contains( "fileX.txt" ) );
163         assertTrue( included.contains( "symR" ) );
164         assertTrue( included.contains( "symW" ) );
165         assertTrue( included.contains( "symX" ) );
166         assertTrue( included.contains( "symLinkToFileOnTheOutside" ) );
167     }
168 
169     @Test
170     public void followSymlinks()
171     {
172         if (!Java7Support.isAtLeastJava7()) return;
173         DirectoryScanner ds = new DirectoryScanner();
174         ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) );
175         ds.setFollowSymlinks( true );
176         ds.scan();
177         List<String> included = Arrays.asList( ds.getIncludedFiles() );
178         assertAlwaysIncluded( included );
179         assertTrue( included.contains( "symDir/targetFile.txt" ) );
180         assertTrue( included.contains( "symLinkToDirOnTheOutside/FileInDirOnTheOutside.txt" ) );
181         assertEquals( 11, included.size() );
182 
183         List<String> includedDirs = Arrays.asList( ds.getIncludedDirectories() );
184         assertTrue( includedDirs.contains( "" ) ); // w00t !
185         assertTrue( includedDirs.contains( "aRegularDir" ) );
186         assertTrue( includedDirs.contains( "symDir" ) );
187         assertTrue( includedDirs.contains( "symLinkToDirOnTheOutside" ) );
188         assertTrue( includedDirs.contains( "targetDir" ) );
189         assertEquals( 5, includedDirs.size() );
190     }
191 
192     @Test
193     public void testSimpleExcludes()
194         throws Exception
195     {
196         createTestData();
197 
198         fitScanTest( true, true, true,
199                 /* includes        */ null,
200                 /* excludes        */ new String[]{ "**/*.dat", "*.somethingelse" },
201                 /* expInclFiles    */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
202                 /* expInclDirs     */ new String[]{ "", "folder1" },
203                 /* expNotInclFiles */ NONE,
204                 /* expNotInclDirs  */ NONE,
205                 /* expExclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
206                 /* expExclDirs     */ NONE );
207 
208         // same without followSymlinks
209         fitScanTest( true, false, true,
210                 /* includes        */ null,
211                 /* excludes        */ new String[]{ "**/*.dat", "*.somethingelse" },
212                 /* expInclFiles    */ new String[]{ "file1.txt", "file2.txt", "folder1/file4.txt" },
213                 /* expInclDirs     */ new String[]{ "", "folder1" },
214                 /* expNotInclFiles */ NONE,
215                 /* expNotInclDirs  */ NONE,
216                 /* expExclFiles    */ new String[]{ "file3.dat", "folder1/file5.dat" },
217                 /* expExclDirs     */ NONE );
218     }
219 
220     public void testIsSymLin()
221         throws IOException
222     {
223         File file = new File( "." );
224         DirectoryScanner ds = new DirectoryScanner();
225         ds.isSymbolicLink( file, "abc" );
226     }
227 
228     /**
229      * Performs a scan and test for the given parameters if not null.
230      */
231     private void fitScanTest( boolean caseSensitive, boolean followSymLinks, boolean addDefaultExcludes,
232                               String[] includes, String[] excludes, String[] expectedIncludedFiles,
233                               String[] expectedIncludedDirectories, String[] expectedNotIncludedFiles,
234                               String[] expectedNotIncludedDirectories, String[] expectedExcludedFiles,
235                               String[] expectedExcludedDirectories )
236     {
237         DirectoryScanner ds = new DirectoryScanner();
238         ds.setBasedir( tempFolder.getRoot() );
239 
240         ds.setCaseSensitive( caseSensitive );
241         ds.setFollowSymlinks( followSymLinks );
242 
243         if ( addDefaultExcludes )
244         {
245             ds.addDefaultExcludes();
246         }
247         if ( includes != null )
248         {
249             ds.setIncludes( includes );
250         }
251         if ( excludes != null )
252         {
253             ds.setExcludes( excludes );
254         }
255 
256         TestScanConductor scanConductor = new TestScanConductor();
257 
258         ds.setScanConductor( scanConductor );
259 
260         ds.scan();
261 
262         checkFiles( "expectedIncludedFiles", expectedIncludedFiles, ds.getIncludedFiles() );
263         checkFiles( "expectedIncludedDirectories", expectedIncludedDirectories, ds.getIncludedDirectories() );
264         checkFiles( "expectedNotIncludedFiles", expectedNotIncludedFiles, ds.getNotIncludedFiles() );
265         checkFiles( "expectedNotIncludedDirectories", expectedNotIncludedDirectories, ds.getNotIncludedDirectories() );
266         checkFiles( "expectedExcludedFiles", expectedExcludedFiles, ds.getExcludedFiles() );
267         checkFiles( "expectedExcludedDirectories", expectedExcludedDirectories, ds.getExcludedDirectories() );
268 
269         checkFiles( "visitedFiles", expectedIncludedFiles,
270                     scanConductor.visitedFiles.toArray( new String[scanConductor.visitedFiles.size()] ) );
271     }
272 
273     /**
274      * Check if the resolved files match the rules of the expected files.
275      *
276      * @param expectedFiles
277      * @param resolvedFiles
278      */
279     private void checkFiles( String category, String[] expectedFiles, String[] resolvedFiles )
280     {
281         if ( expectedFiles != null )
282         {
283             String msg = category + " expected: " + Arrays.toString( expectedFiles ) + " but got: " + Arrays.toString(
284                 resolvedFiles );
285             Assert.assertNotNull( msg, resolvedFiles );
286             assertEquals( msg, expectedFiles.length, resolvedFiles.length );
287 
288             Arrays.sort( expectedFiles );
289             Arrays.sort( resolvedFiles );
290 
291             for ( int i = 0; i < resolvedFiles.length; i++ )
292             {
293                 assertEquals( msg, expectedFiles[i], resolvedFiles[i].replace( "\\", "/" ) );
294             }
295         }
296     }
297 
298     private static class TestScanConductor
299         implements ScanConductor
300     {
301         final List<String> visitedFiles = new ArrayList<String>();
302 
303         public ScanConductor.ScanAction visitDirectory( String name, File directory )
304         {
305             assertTrue( directory.isDirectory() );
306 
307             if ( directory.getName().equals( "ignorefolder" ) )
308             {
309                 return ScanAction.NO_RECURSE;
310             }
311 
312             return ScanAction.CONTINUE;
313         }
314 
315         public ScanConductor.ScanAction visitFile( String name, File file )
316         {
317             assertTrue( file.isFile() );
318             visitedFiles.add( name );
319             return ScanAction.CONTINUE;
320         }
321     }
322 
323     private void removeAndAddSomeFiles()
324         throws IOException
325     {
326         File rootDir = tempFolder.getRoot();
327         File file2 = new File( rootDir, "file2.txt" );
328         file2.delete();
329 
330         FileTestHelper.generateTestFile( new File( rootDir, "folder1/file9.txt" ), 15 );
331 
332         File folder2 = new File( rootDir, "folder1/ignorefolder" );
333         FileUtils.deleteDirectory( folder2 );
334     }
335 
336     @Test
337     public void testScanDiff()
338         throws Exception
339     {
340         createTestData();
341 
342         DirectoryScanner dss = new DirectoryScanner();
343         dss.setBasedir( tempFolder.getRoot() );
344         Assert.assertNotNull( dss );
345 
346         // we take the initial snapshot
347         dss.scan();
348         String[] oldFiles = dss.getIncludedFiles();
349 
350         // now we change 3 files. add one and remove
351         removeAndAddSomeFiles();
352 
353         dss.scan();
354 
355         DirectoryScanResult dsr = dss.diffIncludedFiles( oldFiles );
356 
357         String[] addedFiles = dsr.getFilesAdded();
358         String[] removedFiles = dsr.getFilesRemoved();
359         Assert.assertNotNull( addedFiles );
360         Assert.assertNotNull( removedFiles );
361         assertEquals( 1, addedFiles.length );
362         assertEquals( 2, removedFiles.length );
363     }
364 
365     @Ignore( "Enable this test to run performance checks" ) @Test
366     public void performanceTest()
367         throws Exception
368     {
369 
370         File rootFolder = tempFolder.getRoot();
371 
372         // do some warmup
373         for ( int i = 1; i < 200; i++ )
374         {
375             createTestData();
376             removeAndAddSomeFiles();
377             FileUtils.deleteDirectory( rootFolder );
378         }
379 
380         int cycles = 2000;
381 
382         // and now we take the time _without_
383         long startTime = System.nanoTime();
384         for ( int i = 1; i < cycles; i++ )
385         {
386             createTestData();
387             removeAndAddSomeFiles();
388             FileUtils.deleteDirectory( rootFolder );
389             rootFolder.mkdir();
390         }
391         long endTime = System.nanoTime();
392 
393         long durationEmptyRun = endTime - startTime;
394         System.out.println( "durationEmptyRun            [ns]: " + durationEmptyRun );
395 
396         startTime = System.nanoTime();
397         for ( int i = 1; i < cycles; i++ )
398         {
399             createTestData();
400             DirectoryScanner directoryScanner = new DirectoryScanner();
401             directoryScanner.setBasedir( rootFolder );
402             directoryScanner.scan();
403             String[] oldFiles = directoryScanner.getIncludedFiles();
404 
405             removeAndAddSomeFiles();
406 
407             directoryScanner.scan();
408 
409             DirectoryScanResult directoryScanResult = directoryScanner.diffIncludedFiles( oldFiles );
410             Assert.assertNotNull( directoryScanResult );
411 
412             FileUtils.deleteDirectory( rootFolder );
413             rootFolder.mkdir();
414         }
415         endTime = System.nanoTime();
416 
417         long durationWithSnapshotScanner = endTime - startTime;
418         System.out.println( "durationWithSnapshotScanner [ns]: " + durationWithSnapshotScanner );
419 
420         long dirScannerOverhead = durationWithSnapshotScanner - durationEmptyRun;
421 
422         System.out.println( "Overhead for n cycles [ns]: " + dirScannerOverhead );
423     }
424 
425 }