1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.rolling;
15
16 import static ch.qos.logback.core.CoreConstants.DAILY_DATE_PATTERN;
17 import static org.junit.jupiter.api.Assertions.assertEquals;
18 import static org.junit.jupiter.api.Assertions.assertTrue;
19
20 import java.io.File;
21 import java.io.FileFilter;
22 import java.time.Instant;
23 import java.time.ZoneId;
24 import java.time.ZonedDateTime;
25 import java.util.ArrayList;
26 import java.util.Calendar;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.Date;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35 import java.time.temporal.ChronoUnit;
36
37 import org.junit.jupiter.api.BeforeEach;
38 import org.junit.jupiter.api.Disabled;
39 import org.junit.jupiter.api.Test;
40
41 import ch.qos.logback.core.CoreConstants;
42 import ch.qos.logback.core.pattern.SpacePadder;
43 import ch.qos.logback.core.rolling.helper.RollingCalendar;
44 import ch.qos.logback.core.rolling.testUtil.ScaffoldingForRollingTests;
45 import ch.qos.logback.core.status.testUtil.StatusChecker;
46 import ch.qos.logback.core.util.FileSize;
47 import ch.qos.logback.core.util.FixedRateInvocationGate;
48
49 public class TimeBasedRollingWithArchiveRemoval_Test extends ScaffoldingForRollingTests {
50 String MONTHLY_DATE_PATTERN = "yyyy-MM";
51 String MONTHLY_CRONOLOG_DATE_PATTERN = "yyyy/MM";
52 final String DAILY_CRONOLOG_DATE_PATTERN = "yyyy/MM/dd";
53
54 RollingFileAppender<Object> rfa = new RollingFileAppender<Object>();
55 TimeBasedRollingPolicy<Object> tbrp = new TimeBasedRollingPolicy<Object>();
56
57
58
59 TimeBasedFileNamingAndTriggeringPolicy<Object> tbfnatp = new DefaultTimeBasedFileNamingAndTriggeringPolicy<Object>();
60
61 StatusChecker checker = new StatusChecker(context);
62
63 static long MILLIS_IN_MINUTE = 60 * 1000;
64 static long MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE;
65 static long MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR;
66 static long MILLIS_IN_MONTH = (long) ((365.242199 / 12) * MILLIS_IN_DAY);
67 static int MONTHS_IN_YEAR = 12;
68
69 public static final String DAILY_HOUR_PATTERN = "yyyy-MM-dd-HH";
70
71
72 static final long WED_2016_03_23_T_230705_CET = 1458770825333L;
73 static final long THU_2016_03_17_T_230330_CET = 1458252210975L;
74
75 int slashCount = 0;
76 int ticksPerPeriod = 216;
77
78 ConfigParameters cp;
79 FixedRateInvocationGate fixedRateInvocationGate = new FixedRateInvocationGate(ticksPerPeriod / 2);
80
81 @BeforeEach
82 public void setUp() {
83 super.setUp();
84 this.cp = new ConfigParameters(currentTime);
85 }
86
87 private int computeSlashCount(String datePattern) {
88 if (datePattern == null)
89 return 0;
90 else {
91 int count = 0;
92 for (int i = 0; i < datePattern.length(); i++) {
93 char c = datePattern.charAt(i);
94 if (c == '/')
95 count++;
96 }
97 return count;
98 }
99 }
100
101
102
103
104 @Test
105 public void monthlyRolloverOverManyPeriods() {
106 this.slashCount = computeSlashCount(MONTHLY_CRONOLOG_DATE_PATTERN);
107 int maxHistory = 2;
108 int simulatedNumberOfPeriods = 30;
109 String fileNamePattern = randomOutputDir + "/%d{" + MONTHLY_CRONOLOG_DATE_PATTERN + "}/clean.txt.zip";
110
111 cp.maxHistory(maxHistory).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(simulatedNumberOfPeriods)
112 .periodDurationInMillis(MILLIS_IN_MONTH);
113
114 long startTime = currentTime;
115 long endTime = logOverMultiplePeriods(cp);
116 System.out.println("randomOutputDir:" + randomOutputDir);
117 System.out.println("start:" + startTime + ", end=" + endTime);
118 int differenceInMonths = RollingCalendar.diffInMonths(startTime, endTime);
119 System.out.println("differenceInMonths:" + differenceInMonths);
120 Calendar startTimeAsCalendar = Calendar.getInstance();
121 startTimeAsCalendar.setTimeInMillis(startTime);
122 int indexOfStartPeriod = startTimeAsCalendar.get(Calendar.MONTH);
123 boolean withExtraFolder = extraFolder(differenceInMonths, MONTHS_IN_YEAR, indexOfStartPeriod, maxHistory);
124
125 checkFileCount(expectedCountWithFolders(maxHistory, withExtraFolder));
126 }
127
128 long generateDailyRollover(ConfigParameters cp) {
129 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN);
130 cp.fileNamePattern(randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt");
131 return logOverMultiplePeriods(cp);
132 }
133
134 long generateDailyRolloverAndCheckFileCount(ConfigParameters cp) {
135 long millisAtEnd = generateDailyRollover(cp);
136 int periodBarriersCrossed = computeCrossedDayBarriers(currentTime, millisAtEnd);
137
138 checkFileCount(expectedCountWithoutFoldersWithInactivity(cp.maxHistory, periodBarriersCrossed,
139 cp.startInactivity + cp.numInactivityPeriods));
140 return millisAtEnd;
141 }
142
143 @Test
144 public void checkCrossedPeriodsWithDSTBarrier() {
145 long SAT_2016_03_26_T_230705_CET = WED_2016_03_23_T_230705_CET + 3 * CoreConstants.MILLIS_IN_ONE_DAY;
146 long MON_2016_03_28_T_000705_CET = SAT_2016_03_26_T_230705_CET + CoreConstants.MILLIS_IN_ONE_DAY;
147
148 long result = computeCrossedDayBarriers(SAT_2016_03_26_T_230705_CET, MON_2016_03_28_T_000705_CET, "CET");
149 assertEquals(2, result);
150 }
151
152 private int computeCrossedDayBarriers(long currentTime, long millisAtEnd) {
153 return computeCrossedDayBarriers(currentTime, millisAtEnd, null);
154 }
155
156 private int computeCrossedDayBarriers(long currentTime, long millisAtEnd, String timeZoneID) {
157 ZoneId dateTimeZone = ZoneId.systemDefault();
158 if (timeZoneID != null) {
159 dateTimeZone = ZoneId.of(timeZoneID);
160 }
161
162 Instant startInstant = Instant.ofEpochMilli(currentTime);
163 ZonedDateTime startZDT = startInstant.atZone(dateTimeZone);
164
165 ZonedDateTime startZDT0 = startZDT.truncatedTo(ChronoUnit.DAYS);
166
167 Instant endInstant = Instant.ofEpochMilli(millisAtEnd);
168 ZonedDateTime endZDT = endInstant.atZone(dateTimeZone);
169
170 ZonedDateTime endZDT0 = endZDT.truncatedTo(ChronoUnit.DAYS);
171
172
173 long dayCount = ChronoUnit.DAYS.between(startZDT0, endZDT0);
174 return (int) dayCount;
175 }
176
177 @Test
178 public void checkCleanupForBasicDailyRollover() {
179 cp.maxHistory(20).simulatedNumberOfPeriods(20 * 3).startInactivity(0).numInactivityPeriods(0);
180 generateDailyRolloverAndCheckFileCount(cp);
181 }
182
183 @Test
184 public void checkCleanupForBasicDailyRolloverWithSizeCap() {
185 long bytesOutputPerPeriod = 15984;
186 int sizeInUnitsOfBytesPerPeriod = 2;
187
188 cp.maxHistory(5).simulatedNumberOfPeriods(10)
189 .sizeCap(sizeInUnitsOfBytesPerPeriod * bytesOutputPerPeriod + 1000);
190 generateDailyRollover(cp);
191 checkFileCount(sizeInUnitsOfBytesPerPeriod + 1);
192 }
193
194 @Test
195 public void checkThatSmallTotalSizeCapLeavesAtLeastOneArhcive() {
196 long WED_2016_03_23_T_131345_CET = WED_2016_03_23_T_230705_CET - 10 * CoreConstants.MILLIS_IN_ONE_HOUR;
197
198
199
200 cp = new ConfigParameters(WED_2016_03_23_T_131345_CET);
201 final int verySmallCapSize = 1;
202 cp.maxHistory(5).simulatedNumberOfPeriods(3).sizeCap(verySmallCapSize);
203 generateDailyRollover(cp);
204
205 checkFileCountAtMost(1);
206
207 }
208
209 @Test
210 public void checkCleanupForBasicDailyRolloverWithMaxSize() {
211 cp.maxHistory(6).simulatedNumberOfPeriods(30).startInactivity(10).numInactivityPeriods(1);
212 generateDailyRolloverAndCheckFileCount(cp);
213 }
214
215
216
217
218 @Test
219 public void checkCleanupForDailyRollover_15Periods() {
220 cp.maxHistory(5).simulatedNumberOfPeriods(15).startInactivity(6).numInactivityPeriods(3);
221 generateDailyRolloverAndCheckFileCount(cp);
222 }
223
224 @Test
225 public void checkCleanupForDailyRolloverWithInactivity_30Periods() {
226
227 cp.maxHistory(2).simulatedNumberOfPeriods(30).startInactivity(3).numInactivityPeriods(1);
228 generateDailyRolloverAndCheckFileCount(cp);
229 }
230
231 @Test
232 public void checkCleanupForDailyRolloverWithInactivity_10Periods() {
233 this.currentTime = THU_2016_03_17_T_230330_CET;
234 cp.maxHistory(6).simulatedNumberOfPeriods(10).startInactivity(2).numInactivityPeriods(2);
235 generateDailyRolloverAndCheckFileCount(cp);
236 }
237
238 @Test
239 public void checkCleanupForDailyRolloverWithSecondPhase() {
240 slashCount = computeSlashCount(DAILY_DATE_PATTERN);
241 int maxHistory = 5;
242 String fileNamePattern = randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt";
243
244 ConfigParameters cp0 = new ConfigParameters(currentTime).maxHistory(maxHistory).fileNamePattern(fileNamePattern)
245 .simulatedNumberOfPeriods(maxHistory * 2);
246 long endTime = logOverMultiplePeriods(cp0);
247
248 ConfigParameters cp1 = new ConfigParameters(endTime + MILLIS_IN_DAY * 10).maxHistory(maxHistory)
249 .fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(maxHistory);
250 logOverMultiplePeriods(cp1);
251 checkFileCount(expectedCountWithoutFolders(maxHistory));
252 }
253
254 @Test
255 public void dailyRolloverWithCronologPattern() {
256 this.slashCount = computeSlashCount(DAILY_CRONOLOG_DATE_PATTERN);
257 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_CRONOLOG_DATE_PATTERN + "}/clean.txt.zip";
258 cp.maxHistory(8).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(8 * 3);
259 logOverMultiplePeriods(cp);
260 int expectedDirMin = 9 + slashCount;
261 int expectDirMax = expectedDirMin + 1 + 1;
262 expectedFileAndDirCount(9, expectedDirMin, expectDirMax);
263 }
264
265 @Test
266 public void dailySizeBasedRolloverWithoutCap() {
267 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>();
268 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate;
269
270 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000));
271 tbfnatp = sizeAndTimeBasedFNATP;
272 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN);
273 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}-clean.%i.zip";
274 cp.maxHistory(5).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(5 * 4);
275 logOverMultiplePeriods(cp);
276 checkPatternCompliance(5 + 1 + slashCount, "\\d{4}-\\d{2}-\\d{2}-clean(\\.\\d)(.zip)?");
277 }
278
279 @Test
280 public void dailySizeBasedRolloverWithSizeCap() {
281 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>();
282 sizeAndTimeBasedFNATP.invocationGate = new FixedRateInvocationGate(ticksPerPeriod / 8);
283 long bytesPerPeriod = 17000;
284 long fileSize = (bytesPerPeriod) / 5;
285 int expectedFileCount = 10;
286 long sizeCap = expectedFileCount * fileSize;
287 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(fileSize));
288 tbfnatp = sizeAndTimeBasedFNATP;
289 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN);
290
291
292 long simulatedTime = 1457133279186L;
293 ConfigParameters params = new ConfigParameters(simulatedTime);
294 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}-clean.%i";
295 params.maxHistory(60).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(10).sizeCap(sizeCap);
296 logOverMultiplePeriods(params);
297
298 List<File> foundFiles = findFilesByPattern("\\d{4}-\\d{2}-\\d{2}-clean(\\.\\d)");
299 Collections.sort(foundFiles, new Comparator<File>() {
300 public int compare(File f0, File f1) {
301 String s0 = f0.getName().toString();
302 String s1 = f1.getName().toString();
303 return s0.compareTo(s1);
304 }
305 });
306 checkFileCount(expectedFileCount - 1);
307 }
308
309 @Test
310 public void dailyChronologSizeBasedRollover() {
311 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>();
312 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000));
313 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate;
314 tbfnatp = sizeAndTimeBasedFNATP;
315 slashCount = 1;
316 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}/clean.%i.zip";
317 cp.maxHistory(5).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(5 * 3);
318 logOverMultiplePeriods(cp);
319 checkDirPatternCompliance(6);
320 }
321
322 @Test
323 public void dailyChronologSizeBasedRolloverWithSecondPhase() {
324 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>();
325 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000));
326 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate;
327 tbfnatp = sizeAndTimeBasedFNATP;
328 this.slashCount = 1;
329 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}/clean.%i";
330 int maxHistory = 5;
331 cp.maxHistory(maxHistory).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(3);
332 long endTime = logOverMultiplePeriods(cp);
333
334 int simulatedNumberOfPeriods = maxHistory * 4;
335 ConfigParameters cp1 = new ConfigParameters(endTime + MILLIS_IN_DAY * 7).maxHistory(maxHistory)
336 .fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(simulatedNumberOfPeriods);
337 logOverMultiplePeriods(cp1);
338 checkDirPatternCompliance(maxHistory + 1);
339 }
340
341 void logTwiceAndStop(long currentTime, String fileNamePattern, int maxHistory, long durationInMillis) {
342 ConfigParameters params = new ConfigParameters(currentTime).fileNamePattern(fileNamePattern)
343 .maxHistory(maxHistory);
344 buildRollingFileAppender(params, DO_CLEAN_HISTORY_ON_START);
345 rfa.doAppend("Hello ----------------------------------------------------------" + new Date(currentTime));
346 currentTime += durationInMillis / 2;
347 add(tbrp.compressionFuture);
348 add(tbrp.cleanUpFuture);
349 waitForJobsToComplete();
350 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
351 rfa.doAppend("Hello ----------------------------------------------------------" + new Date(currentTime));
352 rfa.stop();
353 }
354
355
356 @Test
357 public void cleanHistoryOnStartWithHourPattern() {
358 long simulatedTime = WED_2016_03_23_T_230705_CET;
359 String fileNamePattern = randomOutputDir + "clean-%d{" + DAILY_HOUR_PATTERN + "}.txt";
360 int maxHistory = 3;
361 for (int i = 0; i <= 5; i++) {
362 logTwiceAndStop(simulatedTime, fileNamePattern, maxHistory, MILLIS_IN_HOUR);
363 simulatedTime += MILLIS_IN_HOUR;
364 }
365 checkFileCount(expectedCountWithoutFolders(maxHistory));
366 }
367
368 @Disabled
369 @Test
370
371
372
373
374
375
376
377 public void cleanHistoryOnStartWithHourPatternWithCollisions() {
378 long now = this.currentTime;
379 String fileNamePattern = randomOutputDir + "clean-%d{HH}.txt";
380 int maxHistory = 3;
381 for (int i = 0; i <= 5; i++) {
382 logTwiceAndStop(now, fileNamePattern, maxHistory, MILLIS_IN_DAY);
383 now = now + MILLIS_IN_HOUR;
384 }
385 checkFileCount(expectedCountWithoutFolders(maxHistory));
386 }
387
388 @Test
389 public void cleanHistoryOnStartWithDayPattern() {
390 long simulatedTime = WED_2016_03_23_T_230705_CET;
391 String fileNamePattern = randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt";
392 int maxHistory = 3;
393 for (int i = 0; i <= 5; i++) {
394 logTwiceAndStop(simulatedTime, fileNamePattern, maxHistory, MILLIS_IN_DAY);
395 simulatedTime += MILLIS_IN_DAY;
396 }
397 checkFileCount(expectedCountWithoutFolders(maxHistory));
398 }
399
400 @Test
401 public void cleanHistoryOnStartWithHourDayPattern() {
402 long simulatedTime = WED_2016_03_23_T_230705_CET;
403 String fileNamePattern = randomOutputDir + "clean-%d{yyyy-MM-dd-HH}.txt";
404 int maxHistory = 3;
405 for (int i = 0; i <= 5; i++) {
406 logTwiceAndStop(simulatedTime, fileNamePattern, maxHistory, MILLIS_IN_HOUR);
407 simulatedTime += MILLIS_IN_HOUR;
408 }
409 checkFileCount(expectedCountWithoutFolders(maxHistory));
410 }
411
412 int expectedCountWithoutFolders(int maxHistory) {
413 return maxHistory + 1;
414 }
415
416 int expectedCountWithFolders(int maxHistory, boolean withExtraFolder) {
417 int numLogFiles = (maxHistory + 1);
418 int numLogFilesAndFolders = numLogFiles * 2;
419 int result = numLogFilesAndFolders + slashCount;
420 if (withExtraFolder)
421 result += 1;
422 return result;
423 }
424
425 void buildRollingFileAppender(ConfigParameters cp, boolean cleanHistoryOnStart) {
426 rfa.setContext(context);
427 rfa.setEncoder(encoder);
428 tbrp.setContext(context);
429 tbrp.setFileNamePattern(cp.fileNamePattern);
430 tbrp.setMaxHistory(cp.maxHistory);
431 tbrp.setTotalSizeCap(new FileSize(cp.sizeCap));
432 tbrp.setParent(rfa);
433 tbrp.setCleanHistoryOnStart(cleanHistoryOnStart);
434 tbrp.timeBasedFileNamingAndTriggeringPolicy = tbfnatp;
435 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(cp.simulatedTime);
436 tbrp.start();
437 rfa.setRollingPolicy(tbrp);
438 rfa.start();
439 }
440
441 boolean DO_CLEAN_HISTORY_ON_START = true;
442 boolean DO_NOT_CLEAN_HISTORY_ON_START = false;
443
444 long logOverMultiplePeriods(ConfigParameters cp) {
445
446 buildRollingFileAppender(cp, DO_NOT_CLEAN_HISTORY_ON_START);
447
448 int runLength = cp.simulatedNumberOfPeriods * ticksPerPeriod;
449 int startInactivityIndex = cp.startInactivity * ticksPerPeriod;
450 int endInactivityIndex = startInactivityIndex + cp.numInactivityPeriods * ticksPerPeriod;
451 long tickDuration = cp.periodDurationInMillis / ticksPerPeriod;
452
453 for (int i = 0; i <= runLength; i++) {
454 Date currentDate = new Date(tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime());
455 if (i < startInactivityIndex || i > endInactivityIndex) {
456 StringBuilder sb = new StringBuilder("Hello");
457 String currentDateStr = currentDate.toString();
458 String iAsString = Integer.toString(i);
459 sb.append(currentDateStr);
460 SpacePadder.spacePad(sb, 66 + (3 - iAsString.length() - currentDateStr.length()));
461 sb.append(iAsString);
462 rfa.doAppend(sb.toString());
463 }
464
465 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(
466 addTime(tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime(), tickDuration));
467
468 add(tbrp.compressionFuture);
469 add(tbrp.cleanUpFuture);
470 waitForJobsToComplete();
471 }
472
473 try {
474 Thread.sleep(100);
475 } catch (InterruptedException e) {
476
477 e.printStackTrace();
478 }
479 rfa.stop();
480
481
482
483 return tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime();
484 }
485
486 void fillWithChar(StringBuffer sb, char c, int count) {
487 for (int i = 0; i < count; i++) {
488 sb.append(c);
489 }
490 }
491
492 boolean extraFolder(int numPeriods, int periodsPerEra, int beginPeriod, int maxHistory) {
493 int valueOfLastMonth = ((beginPeriod) + numPeriods) % periodsPerEra;
494 return (valueOfLastMonth < maxHistory);
495 }
496
497 long addTime(long time, long timeToWait) {
498 return time + timeToWait;
499 }
500
501 void expectedFileAndDirCount(int expectedFileAndDirCount, int expectedDirCountMin, int expectedDirCountMax) {
502 File dir = new File(randomOutputDir);
503 List<File> fileList = new ArrayList<File>();
504 findFilesInFolderRecursivelyByPatterMatch(dir, fileList, "clean");
505 List<File> dirList = new ArrayList<File>();
506 findAllFoldersInFolderRecursively(dir, dirList);
507 String msg = "expectedDirCountMin=" + expectedDirCountMin + ", expectedDirCountMax=" + expectedDirCountMax
508 + " actual value=" + dirList.size();
509 assertTrue(expectedDirCountMin <= dirList.size() && dirList.size() <= expectedDirCountMax, msg);
510 }
511
512 void checkFileCount(int expectedCount) {
513 File dir = new File(randomOutputDir);
514 List<File> fileList = new ArrayList<File>();
515 findAllDirsOrStringContainsFilesRecursively(dir, fileList, "clean");
516 assertEquals(expectedCount, fileList.size());
517 }
518
519 void checkFileCountAtMost(int expectedCount) {
520 File dir = new File(randomOutputDir);
521 List<File> fileList = new ArrayList<File>();
522 findAllDirsOrStringContainsFilesRecursively(dir, fileList, "clean");
523 int fileListSize = fileList.size();
524
525 assertTrue(fileListSize <= expectedCount, "file list size " + fileListSize + ", expectedCount=" + expectedCount);
526 }
527
528 int expectedCountWithoutFoldersWithInactivity(int maxHistory, int totalPeriods, int endOfInactivity) {
529 int availableHistory = (totalPeriods + 1) - endOfInactivity;
530 int actualHistory = Math.min(availableHistory, maxHistory + 1);
531 return actualHistory;
532 }
533
534 void genericFindMatching(final FileMatchFunction matchFunc, File dir, List<File> fileList, final String pattern,
535 boolean includeDirs) {
536 if (dir.isDirectory()) {
537 File[] matchArray = dir.listFiles(new FileFilter() {
538 public boolean accept(File f) {
539 return f.isDirectory() || matchFunc.match(f, pattern);
540 }
541 });
542 for (File f : matchArray) {
543 if (f.isDirectory()) {
544 if (includeDirs)
545 fileList.add(f);
546 genericFindMatching(matchFunc, f, fileList, pattern, includeDirs);
547 } else
548 fileList.add(f);
549 }
550 }
551 }
552
553 private void findAllFoldersInFolderRecursively(File dir, List<File> fileList) {
554 FileMatchFunction alwaysFalse = new FileMatchFunction() {
555 public boolean match(File f, String pattern) {
556 return false;
557 }
558 };
559 genericFindMatching(alwaysFalse, dir, fileList, null, true);
560 }
561
562 private void findAllDirsOrStringContainsFilesRecursively(File dir, List<File> fileList, String pattern) {
563 FileMatchFunction matchFunction = new FileMatchFunction() {
564 public boolean match(File f, String pattern) {
565 return f.getName().contains(pattern);
566 }
567 };
568 genericFindMatching(matchFunction, dir, fileList, pattern, true);
569 }
570
571 void findFilesInFolderRecursivelyByPatterMatch(File dir, List<File> fileList, String pattern) {
572 FileMatchFunction matchByPattern = new FileMatchFunction() {
573 public boolean match(File f, String pattern) {
574 return f.getName().matches(pattern);
575 }
576 };
577 genericFindMatching(matchByPattern, dir, fileList, pattern, false);
578 }
579
580 Set<String> groupByClass(List<File> fileList, String regex) {
581 Pattern p = Pattern.compile(regex);
582 Set<String> set = new HashSet<String>();
583 for (File f : fileList) {
584 String n = f.getName();
585 Matcher m = p.matcher(n);
586 m.matches();
587 int begin = m.start(1);
588 String reduced = n.substring(0, begin);
589 set.add(reduced);
590 }
591 return set;
592 }
593
594 void checkPatternCompliance(int expectedClassCount, String regex) {
595 Set<String> set = findFilesByPatternClass(regex);
596 assertEquals(expectedClassCount, set.size());
597 }
598
599 private List<File> findFilesByPattern(String regex) {
600 File dir = new File(randomOutputDir);
601 List<File> fileList = new ArrayList<File>();
602 findFilesInFolderRecursivelyByPatterMatch(dir, fileList, regex);
603 return fileList;
604 }
605
606 private Set<String> findFilesByPatternClass(String regex) {
607 List<File> fileList = findFilesByPattern(regex);
608 Set<String> set = groupByClass(fileList, regex);
609 return set;
610 }
611
612 void checkDirPatternCompliance(int expectedClassCount) {
613 File dir = new File(randomOutputDir);
614 List<File> fileList = new ArrayList<File>();
615 findAllFoldersInFolderRecursively(dir, fileList);
616 for (File f : fileList) {
617 assertTrue(f.list().length >= 1);
618 }
619 assertEquals(expectedClassCount, fileList.size());
620 }
621 }