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