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