001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.rolling; 015 016import static ch.qos.logback.core.CoreConstants.DAILY_DATE_PATTERN; 017import static org.junit.Assert.assertEquals; 018import static org.junit.Assert.assertTrue; 019 020import java.io.File; 021import java.io.FileFilter; 022import java.util.ArrayList; 023import java.util.Calendar; 024import java.util.Collections; 025import java.util.Comparator; 026import java.util.Date; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Set; 030import java.util.regex.Matcher; 031import java.util.regex.Pattern; 032 033import org.joda.time.DateTimeZone; 034import org.joda.time.Days; 035import org.joda.time.LocalDate; 036import org.junit.Before; 037import org.junit.Ignore; 038import org.junit.Test; 039 040import ch.qos.logback.core.CoreConstants; 041import ch.qos.logback.core.pattern.SpacePadder; 042import ch.qos.logback.core.rolling.helper.RollingCalendar; 043import ch.qos.logback.core.rolling.testUtil.ScaffoldingForRollingTests; 044import ch.qos.logback.core.testUtil.StatusChecker; 045import ch.qos.logback.core.util.FileSize; 046import ch.qos.logback.core.util.FixedRateInvocationGate; 047import ch.qos.logback.core.util.StatusPrinter; 048 049public class TimeBasedRollingWithArchiveRemoval_Test extends ScaffoldingForRollingTests { 050 String MONTHLY_DATE_PATTERN = "yyyy-MM"; 051 String MONTHLY_CRONOLOG_DATE_PATTERN = "yyyy/MM"; 052 final String DAILY_CRONOLOG_DATE_PATTERN = "yyyy/MM/dd"; 053 054 RollingFileAppender<Object> rfa = new RollingFileAppender<Object>(); 055 TimeBasedRollingPolicy<Object> tbrp = new TimeBasedRollingPolicy<Object>(); 056 057 // by default tbfnatp is an instance of DefaultTimeBasedFileNamingAndTriggeringPolicy 058 TimeBasedFileNamingAndTriggeringPolicy<Object> tbfnatp = new DefaultTimeBasedFileNamingAndTriggeringPolicy<Object>(); 059 060 StatusChecker checker = new StatusChecker(context); 061 062 static long MILLIS_IN_MINUTE = 60 * 1000; 063 static long MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; 064 static long MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; 065 static long MILLIS_IN_MONTH = (long) ((365.242199 / 12) * MILLIS_IN_DAY); 066 static int MONTHS_IN_YEAR = 12; 067 068 // Wed Mar 23 23:07:05 CET 2016 069 static final long WED_2016_03_23_T_230705_CET = 1458770825333L; 070 static final long THU_2016_03_17_T_230330_CET = 1458252210975L; 071 072 int slashCount = 0; 073 int ticksPerPeriod = 216; 074 075 ConfigParameters cp; // initialized in setup 076 FixedRateInvocationGate fixedRateInvocationGate = new FixedRateInvocationGate(ticksPerPeriod / 2); 077 078 @Before 079 public void setUp() { 080 super.setUp(); 081 this.cp = new ConfigParameters(currentTime); 082 } 083 084 private int computeSlashCount(String datePattern) { 085 if (datePattern == null) 086 return 0; 087 else { 088 int count = 0; 089 for (int i = 0; i < datePattern.length(); i++) { 090 char c = datePattern.charAt(i); 091 if (c == '/') 092 count++; 093 } 094 return count; 095 } 096 } 097 098 // test that the number of files at the end of the test is same as the expected number taking into account end dates 099 // near the beginning of a new year. This test has been run in a loop with start date varying over a two years 100 // with success. 101 @Test 102 public void monthlyRolloverOverManyPeriods() { 103 this.slashCount = computeSlashCount(MONTHLY_CRONOLOG_DATE_PATTERN); 104 int maxHistory = 2; 105 int simulatedNumberOfPeriods = 30; 106 String fileNamePattern = randomOutputDir + "/%d{" + MONTHLY_CRONOLOG_DATE_PATTERN + "}/clean.txt.zip"; 107 108 cp.maxHistory(maxHistory).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(simulatedNumberOfPeriods).periodDurationInMillis(MILLIS_IN_MONTH); 109 110 long startTime = currentTime; 111 long endTime = logOverMultiplePeriods(cp); 112 System.out.println("randomOutputDir:" + randomOutputDir); 113 System.out.println("start:" + startTime + ", end=" + endTime); 114 int differenceInMonths = RollingCalendar.diffInMonths(startTime, endTime); 115 System.out.println("differenceInMonths:" + differenceInMonths); 116 Calendar startTimeAsCalendar = Calendar.getInstance(); 117 startTimeAsCalendar.setTimeInMillis(startTime); 118 int indexOfStartPeriod = startTimeAsCalendar.get(Calendar.MONTH); 119 boolean withExtraFolder = extraFolder(differenceInMonths, MONTHS_IN_YEAR, indexOfStartPeriod, maxHistory); 120 121 checkFileCount(expectedCountWithFolders(maxHistory, withExtraFolder)); 122 } 123 124 long generateDailyRollover(ConfigParameters cp) { 125 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN); 126 cp.fileNamePattern(randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt"); 127 return logOverMultiplePeriods(cp); 128 } 129 130 long generateDailyRolloverAndCheckFileCount(ConfigParameters cp) { 131 long millisAtEnd = generateDailyRollover(cp); 132 int periodBarriersCrossed = computeCrossedDayBarriers(currentTime, millisAtEnd); 133 System.out.println("**** periodBarriersCrossed=" + periodBarriersCrossed); 134 checkFileCount(expectedCountWithoutFoldersWithInactivity(cp.maxHistory, periodBarriersCrossed, cp.startInactivity + cp.numInactivityPeriods)); 135 return millisAtEnd; 136 } 137 138 @Test 139 public void checkCrossedPeriodsWithDSTBarrier() { 140 long SAT_2016_03_26_T_230705_CET = WED_2016_03_23_T_230705_CET + 3 * CoreConstants.MILLIS_IN_ONE_DAY; 141 System.out.println("SAT_2016_03_26_T_230705_CET " + new Date(SAT_2016_03_26_T_230705_CET)); 142 long MON_2016_03_28_T_000705_CET = SAT_2016_03_26_T_230705_CET + CoreConstants.MILLIS_IN_ONE_DAY; 143 System.out.println("MON_2016_03_28_T_000705_CET " + new Date(MON_2016_03_28_T_000705_CET)); 144 145 int result = computeCrossedDayBarriers(SAT_2016_03_26_T_230705_CET, MON_2016_03_28_T_000705_CET, "CET"); 146 assertEquals(2, result); 147 } 148 149 private int computeCrossedDayBarriers(long currentTime, long millisAtEnd) { 150 return computeCrossedDayBarriers(currentTime, millisAtEnd, null); 151 } 152 153 private int computeCrossedDayBarriers(long currentTime, long millisAtEnd, String timeZoneID) { 154 DateTimeZone dateTimeZone = DateTimeZone.getDefault(); 155 if (timeZoneID != null) { 156 dateTimeZone = DateTimeZone.forID(timeZoneID); 157 } 158 LocalDate startInstant = new LocalDate(currentTime, dateTimeZone); 159 LocalDate endInstant = new LocalDate(millisAtEnd, dateTimeZone); 160 Days days = Days.daysBetween(startInstant, endInstant); 161 return days.getDays(); 162 } 163 164 @Test 165 public void checkCleanupForBasicDailyRollover() { 166 cp.maxHistory(20).simulatedNumberOfPeriods(20 * 3).startInactivity(0).numInactivityPeriods(0); 167 generateDailyRolloverAndCheckFileCount(cp); 168 } 169 170 @Test 171 public void checkCleanupForBasicDailyRolloverWithSizeCap() { 172 long bytesOutputPerPeriod = 15984; 173 int sizeInUnitsOfBytesPerPeriod = 2; 174 175 cp.maxHistory(5).simulatedNumberOfPeriods(10).sizeCap(sizeInUnitsOfBytesPerPeriod * bytesOutputPerPeriod + 1000); 176 generateDailyRollover(cp); 177 StatusPrinter.print(context); 178 checkFileCount(sizeInUnitsOfBytesPerPeriod + 1); 179 } 180 181 @Test 182 public void checkThatSmallTotalSizeCapLeavesAtLeastOneArhcive() { 183 long WED_2016_03_23_T_131345_CET = WED_2016_03_23_T_230705_CET - 10 * CoreConstants.MILLIS_IN_ONE_HOUR; 184 185 // long bytesOutputPerPeriod = 15984; 186 187 cp = new ConfigParameters(WED_2016_03_23_T_131345_CET); 188 final int verySmallCapSize = 1; 189 cp.maxHistory(5).simulatedNumberOfPeriods(3).sizeCap(verySmallCapSize); 190 generateDailyRollover(cp); 191 StatusPrinter.print(context); 192 checkFileCountAtMost(1); 193 194 } 195 196 @Test 197 public void checkCleanupForBasicDailyRolloverWithMaxSize() { 198 cp.maxHistory(6).simulatedNumberOfPeriods(30).startInactivity(10).numInactivityPeriods(1); 199 generateDailyRolloverAndCheckFileCount(cp); 200 } 201 202 // Since the duration of a month (in seconds) varies from month to month, tests with inactivity period must 203 // be conducted with daily rollover not monthly 204 @Test 205 public void checkCleanupForDailyRollover_15Periods() { 206 cp.maxHistory(5).simulatedNumberOfPeriods(15).startInactivity(6).numInactivityPeriods(3); 207 generateDailyRolloverAndCheckFileCount(cp); 208 } 209 210 @Test 211 public void checkCleanupForDailyRolloverWithInactivity_30Periods() { 212 // / ------- 213 cp.maxHistory(2).simulatedNumberOfPeriods(30).startInactivity(3).numInactivityPeriods(1); 214 generateDailyRolloverAndCheckFileCount(cp); 215 } 216 217 @Test 218 public void checkCleanupForDailyRolloverWithInactivity_10Periods() { 219 this.currentTime = THU_2016_03_17_T_230330_CET; 220 cp.maxHistory(6).simulatedNumberOfPeriods(10).startInactivity(2).numInactivityPeriods(2); 221 generateDailyRolloverAndCheckFileCount(cp); 222 } 223 224 @Test 225 public void checkCleanupForDailyRolloverWithSecondPhase() { 226 slashCount = computeSlashCount(DAILY_DATE_PATTERN); 227 int maxHistory = 5; 228 String fileNamePattern = randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt"; 229 230 ConfigParameters cp0 = new ConfigParameters(currentTime).maxHistory(maxHistory).fileNamePattern(fileNamePattern) 231 .simulatedNumberOfPeriods(maxHistory * 2); 232 long endTime = logOverMultiplePeriods(cp0); 233 234 ConfigParameters cp1 = new ConfigParameters(endTime + MILLIS_IN_DAY * 10).maxHistory(maxHistory).fileNamePattern(fileNamePattern) 235 .simulatedNumberOfPeriods(maxHistory); 236 logOverMultiplePeriods(cp1); 237 checkFileCount(expectedCountWithoutFolders(maxHistory)); 238 } 239 240 @Test 241 public void dailyRolloverWithCronologPattern() { 242 this.slashCount = computeSlashCount(DAILY_CRONOLOG_DATE_PATTERN); 243 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_CRONOLOG_DATE_PATTERN + "}/clean.txt.zip"; 244 cp.maxHistory(8).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(8 * 3); 245 logOverMultiplePeriods(cp); 246 int expectedDirMin = 9 + slashCount; 247 int expectDirMax = expectedDirMin + 1 + 1; 248 expectedFileAndDirCount(9, expectedDirMin, expectDirMax); 249 } 250 251 @Test 252 public void dailySizeBasedRolloverWithoutCap() { 253 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>(); 254 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate; 255 256 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000)); 257 tbfnatp = sizeAndTimeBasedFNATP; 258 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN); 259 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}-clean.%i.zip"; 260 cp.maxHistory(5).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(5 * 4); 261 logOverMultiplePeriods(cp); 262 checkPatternCompliance(5 + 1 + slashCount, "\\d{4}-\\d{2}-\\d{2}-clean(\\.\\d)(.zip)?"); 263 } 264 265 @Test 266 public void dailySizeBasedRolloverWithSizeCap() { 267 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>(); 268 sizeAndTimeBasedFNATP.invocationGate = new FixedRateInvocationGate(ticksPerPeriod / 8); 269 long bytesPerPeriod = 17000; 270 long fileSize = (bytesPerPeriod) / 5; 271 int expectedFileCount = 10; 272 long sizeCap = expectedFileCount * fileSize; 273 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(fileSize)); 274 tbfnatp = sizeAndTimeBasedFNATP; 275 this.slashCount = computeSlashCount(DAILY_DATE_PATTERN); 276 277 // 2016-03-05 00:14:39 CET 278 long simulatedTime = 1457133279186L; 279 ConfigParameters params = new ConfigParameters(simulatedTime); 280 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}-clean.%i"; 281 params.maxHistory(60).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(10).sizeCap(sizeCap); 282 logOverMultiplePeriods(params); 283 284 List<File> foundFiles = findFilesByPattern("\\d{4}-\\d{2}-\\d{2}-clean(\\.\\d)"); 285 Collections.sort(foundFiles, new Comparator<File>() { 286 public int compare(File f0, File f1) { 287 String s0 = f0.getName().toString(); 288 String s1 = f1.getName().toString(); 289 return s0.compareTo(s1); 290 } 291 }); 292 System.out.print(foundFiles); 293 StatusPrinter.print(context); 294 checkFileCount(expectedFileCount - 1); 295 } 296 297 @Test 298 public void dailyChronologSizeBasedRollover() { 299 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>(); 300 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000)); 301 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate; 302 tbfnatp = sizeAndTimeBasedFNATP; 303 slashCount = 1; 304 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}/clean.%i.zip"; 305 cp.maxHistory(5).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(5 * 3); 306 logOverMultiplePeriods(cp); 307 checkDirPatternCompliance(6); 308 } 309 310 @Test 311 public void dailyChronologSizeBasedRolloverWithSecondPhase() { 312 SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>(); 313 sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10000)); 314 sizeAndTimeBasedFNATP.invocationGate = fixedRateInvocationGate; 315 tbfnatp = sizeAndTimeBasedFNATP; 316 this.slashCount = 1; 317 String fileNamePattern = randomOutputDir + "/%d{" + DAILY_DATE_PATTERN + "}/clean.%i"; 318 int maxHistory = 5; 319 cp.maxHistory(maxHistory).fileNamePattern(fileNamePattern).simulatedNumberOfPeriods(3); 320 long endTime = logOverMultiplePeriods(cp); 321 322 int simulatedNumberOfPeriods = maxHistory * 4; 323 ConfigParameters cp1 = new ConfigParameters(endTime + MILLIS_IN_DAY * 7).maxHistory(maxHistory).fileNamePattern(fileNamePattern) 324 .simulatedNumberOfPeriods(simulatedNumberOfPeriods); 325 logOverMultiplePeriods(cp1); 326 checkDirPatternCompliance(maxHistory + 1); 327 } 328 329 void logTwiceAndStop(long currentTime, String fileNamePattern, int maxHistory) { 330 ConfigParameters params = new ConfigParameters(currentTime).fileNamePattern(fileNamePattern).maxHistory(maxHistory); 331 buildRollingFileAppender(params, DO_CLEAN_HISTORY_ON_START); 332 rfa.doAppend("Hello ----------------------------------------------------------" + new Date(currentTime)); 333 currentTime += MILLIS_IN_DAY / 2; 334 add(tbrp.compressionFuture); 335 add(tbrp.cleanUpFuture); 336 waitForJobsToComplete(); 337 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime); 338 rfa.doAppend("Hello ----------------------------------------------------------" + new Date(currentTime)); 339 rfa.stop(); 340 } 341 342 @Test 343 public void cleanHistoryOnStart() { 344 long simulatedTime = WED_2016_03_23_T_230705_CET; 345 System.out.println(new Date(simulatedTime)); 346 347 String fileNamePattern = randomOutputDir + "clean-%d{" + DAILY_DATE_PATTERN + "}.txt"; 348 int maxHistory = 3; 349 for (int i = 0; i <= 5; i++) { 350 logTwiceAndStop(simulatedTime, fileNamePattern, maxHistory); 351 simulatedTime += MILLIS_IN_DAY; 352 } 353 StatusPrinter.print(context); 354 checkFileCount(expectedCountWithoutFolders(maxHistory)); 355 } 356 357 @Test 358 public void cleanHistoryOnStartWithDayPattern() { 359 long simulatedTime = WED_2016_03_23_T_230705_CET; 360 String fileNamePattern = randomOutputDir + "clean-%d{yyyy-MM-dd}.txt"; 361 int maxHistory = 3; 362 for (int i = 0; i <= 5; i++) { 363 logTwiceAndStop(simulatedTime, fileNamePattern, maxHistory); 364 simulatedTime += MILLIS_IN_DAY; 365 } 366 StatusPrinter.print(context); 367 checkFileCount(expectedCountWithoutFolders(maxHistory)); 368 } 369 370 @Ignore 371 @Test 372 // this test assumes a high degree of collisions in the archived files. Every 24 hours, the archive 373 // belonging to the previous day will be overwritten. Given that logback goes 14 days (336 hours) in history 374 // to clean files on start up, it is bound to delete more recent files. It is not logback's responsibility 375 // to cater for such degenerate cases. 376 public void cleanHistoryOnStartWithHourPattern() { 377 long now = this.currentTime; 378 String fileNamePattern = randomOutputDir + "clean-%d{HH}.txt"; 379 int maxHistory = 3; 380 for (int i = 0; i <= 5; i++) { 381 logTwiceAndStop(now, fileNamePattern, maxHistory); 382 now = now + MILLIS_IN_HOUR; 383 } 384 StatusPrinter.print(context); 385 checkFileCount(expectedCountWithoutFolders(maxHistory)); 386 } 387 388 int expectedCountWithoutFolders(int maxHistory) { 389 return maxHistory + 1; 390 } 391 392 int expectedCountWithFolders(int maxHistory, boolean withExtraFolder) { 393 int numLogFiles = (maxHistory + 1); 394 int numLogFilesAndFolders = numLogFiles * 2; 395 int result = numLogFilesAndFolders + slashCount; 396 if (withExtraFolder) 397 result += 1; 398 return result; 399 } 400 401 void buildRollingFileAppender(ConfigParameters cp, boolean cleanHistoryOnStart) { 402 rfa.setContext(context); 403 rfa.setEncoder(encoder); 404 tbrp.setContext(context); 405 tbrp.setFileNamePattern(cp.fileNamePattern); 406 tbrp.setMaxHistory(cp.maxHistory); 407 tbrp.setTotalSizeCap(new FileSize(cp.sizeCap)); 408 tbrp.setParent(rfa); 409 tbrp.setCleanHistoryOnStart(cleanHistoryOnStart); 410 tbrp.timeBasedFileNamingAndTriggeringPolicy = tbfnatp; 411 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(cp.simulatedTime); 412 tbrp.start(); 413 rfa.setRollingPolicy(tbrp); 414 rfa.start(); 415 } 416 417 boolean DO_CLEAN_HISTORY_ON_START = true; 418 boolean DO_NOT_CLEAN_HISTORY_ON_START = false; 419 420 long logOverMultiplePeriods(ConfigParameters cp) { 421 422 buildRollingFileAppender(cp, DO_NOT_CLEAN_HISTORY_ON_START); 423 424 int runLength = cp.simulatedNumberOfPeriods * ticksPerPeriod; 425 int startInactivityIndex = cp.startInactivity * ticksPerPeriod; 426 int endInactivityIndex = startInactivityIndex + cp.numInactivityPeriods * ticksPerPeriod; 427 long tickDuration = cp.periodDurationInMillis / ticksPerPeriod; 428 429 System.out.println("cp.periodDurationInMillis=" + cp.periodDurationInMillis + ", tickDuration=:" + tickDuration + ", runLength=" + runLength); 430 for (int i = 0; i <= runLength; i++) { 431 Date currentDate = new Date(tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime()); 432 if (i < startInactivityIndex || i > endInactivityIndex) { 433 StringBuilder sb = new StringBuilder("Hello"); 434 String currentDateStr = currentDate.toString(); 435 String iAsString = Integer.toString(i); 436 sb.append(currentDateStr); 437 SpacePadder.spacePad(sb, 66 + (3 - iAsString.length() - currentDateStr.length())); 438 sb.append(iAsString); 439 rfa.doAppend(sb.toString()); 440 } 441 442 tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(addTime(tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime(), tickDuration)); 443 444 add(tbrp.compressionFuture); 445 add(tbrp.cleanUpFuture); 446 waitForJobsToComplete(); 447 } 448 449 450 try { 451 Thread.sleep(100); 452 } catch (InterruptedException e) { 453 // TODO Auto-generated catch block 454 e.printStackTrace(); 455 } 456 rfa.stop(); 457 458 System.out.println("Current time at end of loop: "+new Date(tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); 459 return tbrp.timeBasedFileNamingAndTriggeringPolicy.getCurrentTime(); 460 } 461 462 void fillWithChar(StringBuffer sb, char c, int count) { 463 for (int i = 0; i < count; i++) { 464 sb.append(c); 465 } 466 } 467 468 boolean extraFolder(int numPeriods, int periodsPerEra, int beginPeriod, int maxHistory) { 469 int valueOfLastMonth = ((beginPeriod) + numPeriods) % periodsPerEra; 470 return (valueOfLastMonth < maxHistory); 471 } 472 473 long addTime(long time, long timeToWait) { 474 return time + timeToWait; 475 } 476 477 void expectedFileAndDirCount(int expectedFileAndDirCount, int expectedDirCountMin, int expectedDirCountMax) { 478 File dir = new File(randomOutputDir); 479 List<File> fileList = new ArrayList<File>(); 480 findFilesInFolderRecursivelyByPatterMatch(dir, fileList, "clean"); 481 List<File> dirList = new ArrayList<File>(); 482 findAllFoldersInFolderRecursively(dir, dirList); 483 String msg = "expectedDirCountMin=" + expectedDirCountMin + ", expectedDirCountMax=" + expectedDirCountMax + " actual value=" + dirList.size(); 484 assertTrue(msg, expectedDirCountMin <= dirList.size() && dirList.size() <= expectedDirCountMax); 485 } 486 487 void checkFileCount(int expectedCount) { 488 File dir = new File(randomOutputDir); 489 List<File> fileList = new ArrayList<File>(); 490 findAllDirsOrStringContainsFilesRecursively(dir, fileList, "clean"); 491 assertEquals(expectedCount, fileList.size()); 492 } 493 494 void checkFileCountAtMost(int expectedCount) { 495 File dir = new File(randomOutputDir); 496 List<File> fileList = new ArrayList<File>(); 497 findAllDirsOrStringContainsFilesRecursively(dir, fileList, "clean"); 498 int fileListSize = fileList.size(); 499 500 assertTrue("file list size "+ fileListSize+", expectedCount="+expectedCount, fileListSize <= expectedCount); 501 } 502 503 int expectedCountWithoutFoldersWithInactivity(int maxHistory, int totalPeriods, int endOfInactivity) { 504 int availableHistory = (totalPeriods + 1) - endOfInactivity; 505 int actualHistory = Math.min(availableHistory, maxHistory + 1); 506 return actualHistory; 507 } 508 509 void genericFindMatching(final FileMatchFunction matchFunc, File dir, List<File> fileList, final String pattern, boolean includeDirs) { 510 if (dir.isDirectory()) { 511 File[] matchArray = dir.listFiles(new FileFilter() { 512 public boolean accept(File f) { 513 return f.isDirectory() || matchFunc.match(f, pattern); 514 } 515 }); 516 for (File f : matchArray) { 517 if (f.isDirectory()) { 518 if (includeDirs) 519 fileList.add(f); 520 genericFindMatching(matchFunc, f, fileList, pattern, includeDirs); 521 } else 522 fileList.add(f); 523 } 524 } 525 } 526 527 private void findAllFoldersInFolderRecursively(File dir, List<File> fileList) { 528 FileMatchFunction alwaysFalse = new FileMatchFunction() { 529 public boolean match(File f, String pattern) { 530 return false; 531 } 532 }; 533 genericFindMatching(alwaysFalse, dir, fileList, null, true); 534 } 535 536 private void findAllDirsOrStringContainsFilesRecursively(File dir, List<File> fileList, String pattern) { 537 FileMatchFunction matchFunction = new FileMatchFunction() { 538 public boolean match(File f, String pattern) { 539 return f.getName().contains(pattern); 540 } 541 }; 542 genericFindMatching(matchFunction, dir, fileList, pattern, true); 543 } 544 545 void findFilesInFolderRecursivelyByPatterMatch(File dir, List<File> fileList, String pattern) { 546 FileMatchFunction matchByPattern = new FileMatchFunction() { 547 public boolean match(File f, String pattern) { 548 return f.getName().matches(pattern); 549 } 550 }; 551 genericFindMatching(matchByPattern, dir, fileList, pattern, false); 552 } 553 554 Set<String> groupByClass(List<File> fileList, String regex) { 555 Pattern p = Pattern.compile(regex); 556 Set<String> set = new HashSet<String>(); 557 for (File f : fileList) { 558 String n = f.getName(); 559 Matcher m = p.matcher(n); 560 m.matches(); 561 int begin = m.start(1); 562 String reduced = n.substring(0, begin); 563 set.add(reduced); 564 } 565 return set; 566 } 567 568 void checkPatternCompliance(int expectedClassCount, String regex) { 569 Set<String> set = findFilesByPatternClass(regex); 570 assertEquals(expectedClassCount, set.size()); 571 } 572 573 private List<File> findFilesByPattern(String regex) { 574 File dir = new File(randomOutputDir); 575 List<File> fileList = new ArrayList<File>(); 576 findFilesInFolderRecursivelyByPatterMatch(dir, fileList, regex); 577 return fileList; 578 } 579 580 private Set<String> findFilesByPatternClass(String regex) { 581 List<File> fileList = findFilesByPattern(regex); 582 Set<String> set = groupByClass(fileList, regex); 583 return set; 584 } 585 586 void checkDirPatternCompliance(int expectedClassCount) { 587 File dir = new File(randomOutputDir); 588 List<File> fileList = new ArrayList<File>(); 589 findAllFoldersInFolderRecursively(dir, fileList); 590 for (File f : fileList) { 591 assertTrue(f.list().length >= 1); 592 } 593 assertEquals(expectedClassCount, fileList.size()); 594 } 595}