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 }