View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.rolling.testUtil;
15  
16  import ch.qos.logback.core.Context;
17  import ch.qos.logback.core.ContextBase;
18  import ch.qos.logback.core.encoder.EchoEncoder;
19  import ch.qos.logback.core.rolling.helper.FileFilterUtil;
20  import ch.qos.logback.core.rolling.helper.FileNamePattern;
21  import ch.qos.logback.core.testUtil.CoreTestConstants;
22  import ch.qos.logback.core.testUtil.FileToBufferUtil;
23  import ch.qos.logback.core.testUtil.RandomUtil;
24  
25  import java.io.File;
26  import java.io.IOException;
27  import java.sql.Date;
28  import java.text.SimpleDateFormat;
29  import java.util.ArrayList;
30  import java.util.Calendar;
31  import java.util.Enumeration;
32  import java.util.List;
33  import java.util.concurrent.Future;
34  import java.util.concurrent.TimeUnit;
35  import java.util.function.UnaryOperator;
36  import java.util.zip.ZipEntry;
37  import java.util.zip.ZipFile;
38  
39  import static org.junit.jupiter.api.Assertions.assertEquals;
40  import static org.junit.jupiter.api.Assertions.assertTrue;
41  
42  /**
43   * Scaffolding for various rolling tests. Some assumptions are made: - rollover
44   * periodicity is 1 second (without precluding size based roll-over)
45   *
46   * @author Ceki Gülcü
47   */
48  public class ScaffoldingForRollingTests {
49  
50      static public final String DATE_PATTERN_WITH_SECONDS = "yyyy-MM-dd_HH_mm_ss";
51      static public final String DATE_PATTERN_BY_DAY = "yyyy-MM-dd";
52      static public final SimpleDateFormat SDF = new SimpleDateFormat(DATE_PATTERN_WITH_SECONDS);
53  
54      int diff = RandomUtil.getPositiveInt();
55      protected String randomOutputDir = CoreTestConstants.OUTPUT_DIR_PREFIX + diff + "/";
56      protected EchoEncoder<Object> encoder = new EchoEncoder<Object>();
57      protected Context context = new ContextBase();
58      protected List<String> expectedFilenameList = new ArrayList<String>();
59      protected long nextRolloverThreshold; // initialized in setUp()
60      protected long currentTime; // initialized in setUp()
61      protected List<Future<?>> futureList = new ArrayList<Future<?>>();
62  
63      Calendar calendar = Calendar.getInstance();
64  
65      public void setUp() {
66          context.setName("test");
67          calendar.set(Calendar.MILLISECOND, 333);
68          currentTime = calendar.getTimeInMillis();
69          recomputeRolloverThreshold(currentTime);
70      }
71  
72      public static void existenceCheck(String filename) {
73          assertTrue(new File(filename).exists(), "File " + filename + " does not exist");
74      }
75  
76      public static File[] getFilesInDirectory(String outputDirStr) {
77          File outputDir = new File(outputDirStr);
78          return outputDir.listFiles();
79      }
80  
81      public static void fileContentCheck(File[] fileArray, int runLength, String prefix) throws IOException {
82          fileContentCheck(fileArray, runLength, prefix, 0);
83      }
84  
85      public static void fileContentCheck(File[] fileArray, int runLength, String prefix, int runStart)
86              throws IOException {
87          List<String> stringList = new ArrayList<String>();
88          for (File file : fileArray) {
89              FileToBufferUtil.readIntoList(file, stringList);
90          }
91  
92          List<String> witnessList = new ArrayList<String>();
93  
94          for (int i = runStart; i < runLength; i++) {
95              witnessList.add(prefix + i);
96          }
97          assertEquals(witnessList, stringList);
98      }
99  
100     public static void sortedContentCheck(String outputDirStr, int runLength, String prefix) throws IOException {
101         sortedContentCheck(outputDirStr, runLength, prefix, 0);
102     }
103 
104     public static void sortedContentCheck(String outputDirStr, int runLength, String prefix, int runStart)
105             throws IOException {
106         File[] fileArray = getFilesInDirectory(outputDirStr);
107         FileFilterUtil.sortFileArrayByName(fileArray);
108         fileContentCheck(fileArray, runLength, prefix, runStart);
109     }
110 
111     public static void reverseSortedContentCheck(String outputDirStr, int runLength, String prefix) throws IOException {
112         File[] fileArray = getFilesInDirectory(outputDirStr);
113         FileFilterUtil.reverseSortFileArrayByName(fileArray);
114         fileContentCheck(fileArray, runLength, prefix);
115     }
116 
117     public static void existenceCheck(List<String> filenameList) {
118         for (String filename : filenameList) {
119             assertTrue(new File(filename).exists(), "File " + filename + " does not exist");
120         }
121     }
122 
123     public static int existenceCount(List<String> filenameList) {
124         int existenceCounter = 0;
125         for (String filename : filenameList) {
126             if (new File(filename).exists()) {
127                 existenceCounter++;
128             }
129         }
130         return existenceCounter;
131     }
132 
133     protected String nullFileName(String testId) {
134         return null;
135     }
136 
137     protected String impossibleFileName(String testId) {
138         throw new RuntimeException("implement");
139     }
140 
141     protected String testId2FileName(String testId) {
142         return randomOutputDir + testId + ".log";
143     }
144 
145     // assuming rollover every second
146     protected void recomputeRolloverThreshold(long ct) {
147         long delta = ct % 1000;
148         nextRolloverThreshold = (ct - delta) + 1000;
149     }
150 
151     protected boolean passThresholdTime(long nextRolloverThreshold) {
152         return currentTime >= nextRolloverThreshold;
153     }
154 
155     protected void incCurrentTime(long increment) {
156         currentTime += increment;
157     }
158 
159     protected Date getDateOfCurrentPeriodsStart() {
160         long delta = currentTime % 1000;
161         return new Date(currentTime - delta);
162     }
163 
164     protected Date getDateOfPreviousPeriodsStart() {
165         long delta = currentTime % 1000;
166         return new Date(currentTime - delta - 1000);
167     }
168 
169     protected long getMillisOfCurrentPeriodsStart() {
170         long delta = currentTime % 1000;
171         return (currentTime - delta);
172     }
173 
174     protected void addExpectedFileName_ByDate(String patternStr, long millis) {
175         FileNamePattern fileNamePattern = new FileNamePattern(patternStr, context);
176         String fn = fileNamePattern.convert(new Date(millis));
177         expectedFilenameList.add(fn);
178     }
179 
180     protected void addExpectedFileNamedIfItsTime_ByDate(String fileNamePatternStr) {
181         if (passThresholdTime(nextRolloverThreshold)) {
182             addExpectedFileName_ByDate(fileNamePatternStr, getMillisOfCurrentPeriodsStart());
183             recomputeRolloverThreshold(currentTime);
184         }
185     }
186 
187     protected void addExpectedFileName_ByDate(String outputDir, String testId, Date date, boolean gzExtension) {
188 
189         String fn = outputDir + testId + "-" + SDF.format(date);
190         if (gzExtension) {
191             fn += ".gz";
192         }
193         expectedFilenameList.add(fn);
194     }
195 
196     protected void addExpectedFileName_ByFileIndexCounter(String randomOutputDir, String testId, long millis,
197             int fileIndexCounter, String compressionSuffix) {
198         String fn = randomOutputDir + testId + "-" + SDF.format(millis) + "-" + fileIndexCounter + ".txt"
199                 + compressionSuffix;
200         expectedFilenameList.add(fn);
201     }
202 
203     protected List<String> filterElementsInListBySuffix(String suffix) {
204         List<String> zipFiles = new ArrayList<String>();
205         for (String filename : expectedFilenameList) {
206             if (filename.endsWith(suffix))
207                 zipFiles.add(filename);
208         }
209         return zipFiles;
210     }
211 
212     protected void addExpectedFileNamedIfItsTime_ByDate(String outputDir, String testId, boolean gzExtension) {
213         if (passThresholdTime(nextRolloverThreshold)) {
214             addExpectedFileName_ByDate(outputDir, testId, getDateOfCurrentPeriodsStart(), gzExtension);
215             recomputeRolloverThreshold(currentTime);
216         }
217     }
218 
219     protected void massageExpectedFilesToCorresponToCurrentTarget(String testId,
220             UnaryOperator<String> filenameFunction) {
221         int lastIndex = expectedFilenameList.size() - 1;
222         String last = expectedFilenameList.remove(lastIndex);
223 
224         String filename = filenameFunction.apply(testId);
225         if (filename != null) {
226             expectedFilenameList.add(filename);
227         } else if (last.endsWith(".gz")) {
228             int lastLen = last.length();
229             String stem = last.substring(0, lastLen - 3);
230             expectedFilenameList.add(stem);
231         }
232     }
233 
234     String addGZIfNotLast(int i) {
235         int lastIndex = expectedFilenameList.size() - 1;
236         if (i != lastIndex) {
237             return ".gz";
238         } else {
239             return "";
240         }
241     }
242 
243     protected void zipEntryNameCheck(List<String> expectedFilenameList, String pattern) throws IOException {
244         for (String filepath : expectedFilenameList) {
245             checkZipEntryName(filepath, pattern);
246         }
247     }
248 
249     protected void checkZipEntryMatchesZipFilename(List<String> expectedFilenameList) throws IOException {
250         for (String filepath : expectedFilenameList) {
251             String stripped = stripStemFromZipFilename(filepath);
252             checkZipEntryName(filepath, stripped);
253         }
254     }
255 
256     String stripStemFromZipFilename(String filepath) {
257         File filepathAsFile = new File(filepath);
258         String stem = filepathAsFile.getName();
259         int stemLen = stem.length();
260         return stem.substring(0, stemLen - ".zip".length());
261 
262     }
263 
264     void checkZipEntryName(String filepath, String pattern) throws IOException {
265         ZipFile zf = new ZipFile(filepath);
266 
267         try {
268             Enumeration<? extends ZipEntry> entries = zf.entries();
269             assert ((entries.hasMoreElements()));
270             ZipEntry firstZipEntry = entries.nextElement();
271             assert ((!entries.hasMoreElements()));
272             assertTrue(firstZipEntry.getName().matches(pattern));
273         } finally {
274             if (zf != null)
275                 zf.close();
276         }
277     }
278 
279     protected void add(Future<?> future) {
280         if (future == null)
281             return;
282         if (!futureList.contains(future)) {
283             futureList.add(future);
284         }
285     }
286 
287     protected void waitForJobsToComplete() {
288         for (Future<?> future : futureList) {
289             try {
290                 future.get(10, TimeUnit.SECONDS);
291             } catch (Exception e) {
292                 new RuntimeException("unexpected exception while testing", e);
293             }
294         }
295         futureList.clear();
296     }
297 }