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