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;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.util.Date;
19  import java.util.List;
20  import java.util.concurrent.ExecutionException;
21  import java.util.function.UnaryOperator;
22  
23  import ch.qos.logback.core.util.Duration;
24  import ch.qos.logback.core.util.StatusPrinter;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  
28  import ch.qos.logback.core.encoder.EchoEncoder;
29  import ch.qos.logback.core.rolling.testUtil.ScaffoldingForRollingTests;
30  import ch.qos.logback.core.status.InfoStatus;
31  import ch.qos.logback.core.status.StatusManager;
32  import ch.qos.logback.core.status.testUtil.StatusChecker;
33  import ch.qos.logback.core.util.FileSize;
34  
35  import static org.junit.jupiter.api.Assertions.assertFalse;
36  
37  public class SizeAndTimeBasedFNATP_Test extends ScaffoldingForRollingTests {
38      private SizeAndTimeBasedFNATP<Object> sizeAndTimeBasedFNATP = null;
39      private RollingFileAppender<Object> rfa1 = new RollingFileAppender<Object>();
40      private TimeBasedRollingPolicy<Object> tbrp1 = new TimeBasedRollingPolicy<Object>();
41      private RollingFileAppender<Object> rfa2 = new RollingFileAppender<Object>();
42      private TimeBasedRollingPolicy<Object> tbrp2 = new TimeBasedRollingPolicy<Object>();
43  
44      private EchoEncoder<Object> encoder = new EchoEncoder<Object>();
45      int fileSize = 0;
46      int fileIndexCounter = 0;
47      int sizeThreshold = 0;
48  
49      @BeforeEach
50      public void setUp() {
51          super.setUp();
52      }
53  
54      private void initRollingFileAppender(RollingFileAppender<Object> rfa, String filename) {
55          rfa.setContext(context);
56          rfa.setEncoder(encoder);
57          if (filename != null) {
58              rfa.setFile(filename);
59          }
60      }
61  
62      private void initPolicies(RollingFileAppender<Object> rfa, TimeBasedRollingPolicy<Object> tbrp,
63              String filenamePattern, int sizeThreshold, long givenTime, long lastCheck) {
64          sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<Object>();
65          sizeAndTimeBasedFNATP.setCheckIncrement(Duration.buildByMilliseconds(10));
66          tbrp.setContext(context);
67          sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(sizeThreshold));
68          tbrp.setTimeBasedFileNamingAndTriggeringPolicy(sizeAndTimeBasedFNATP);
69          tbrp.setFileNamePattern(filenamePattern);
70          tbrp.setParent(rfa);
71          tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(givenTime);
72          rfa.setRollingPolicy(tbrp);
73          tbrp.start();
74          rfa.start();
75      }
76  
77      private void addExpectedFileNamedIfItsTime(String randomOutputDir, String testId, String msg,
78              String compressionSuffix) {
79          fileSize = fileSize + msg.getBytes().length;
80          if (passThresholdTime(nextRolloverThreshold)) {
81              fileIndexCounter = 0;
82              fileSize = 0;
83              addExpectedFileName_ByFileIndexCounter(randomOutputDir, testId, getMillisOfCurrentPeriodsStart(),
84                      fileIndexCounter, compressionSuffix);
85              recomputeRolloverThreshold(currentTime);
86              return;
87          }
88  
89          // windows can delay file size changes, so we only allow for fileIndexCounter 0
90          if ((fileIndexCounter == 0) && fileSize > sizeThreshold) {
91              addExpectedFileName_ByFileIndexCounter(randomOutputDir, testId, getMillisOfCurrentPeriodsStart(),
92                      fileIndexCounter, compressionSuffix);
93              fileIndexCounter = fileIndexCounter + 1;
94              fileSize = 0;
95          }
96      }
97  
98      void generic(String testId, UnaryOperator<String> filenameFunction, boolean withSecondPhase,
99              String compressionSuffix) throws IOException, InterruptedException, ExecutionException {
100         String file = filenameFunction.apply(testId);
101         initRollingFileAppender(rfa1, file);
102         sizeThreshold = 300;
103 
104         initPolicies(rfa1, tbrp1,
105                 randomOutputDir + testId + "-%d{" + DATE_PATTERN_WITH_SECONDS + "}-%i.txt" + compressionSuffix,
106                 sizeThreshold, currentTime, 0);
107         addExpectedFileName_ByFileIndexCounter(randomOutputDir, testId, getMillisOfCurrentPeriodsStart(),
108                 fileIndexCounter, compressionSuffix);
109         incCurrentTime(100);
110         tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
111         int runLength = 100;
112         String prefix = "Hello -----------------";
113 
114         for (int i = 0; i < runLength; i++) {
115             String msg = prefix + i;
116             rfa1.doAppend(msg);
117             addExpectedFileNamedIfItsTime(randomOutputDir, testId, msg, compressionSuffix);
118             incCurrentTime(20);
119             tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
120             add(tbrp1.compressionFuture);
121             add(tbrp1.cleanUpFuture);
122         }
123 
124         if (withSecondPhase) {
125             secondPhase(testId, filenameFunction, compressionSuffix, runLength, prefix);
126             runLength = runLength * 2;
127         }
128 
129         if (file != null)
130             massageExpectedFilesToCorresponToCurrentTarget(testId, this::testId2FileName);
131 
132         Thread.yield();
133         // wait for compression to finish
134         waitForJobsToComplete();
135 
136         //StatusPrinter.print(context);
137         existenceCheck(expectedFilenameList);
138         sortedContentCheck(randomOutputDir, runLength, prefix);
139     }
140 
141     void secondPhase(String testId, UnaryOperator<String> filenameFunction, String compressionSuffix, int runLength,
142             String prefix) {
143         rfa1.stop();
144 
145         String filename = filenameFunction.apply(testId);
146         if (filename != null) {
147             File f = new File(filename);
148             f.setLastModified(currentTime);
149         }
150 
151         StatusManager sm = context.getStatusManager();
152         sm.add(new InfoStatus("Time when rfa1 is stopped: " + new Date(currentTime), this));
153         sm.add(new InfoStatus("currentTime%1000=" + (currentTime % 1000), this));
154 
155         initRollingFileAppender(rfa2, filename);
156         initPolicies(rfa2, tbrp2,
157                 randomOutputDir + testId + "-%d{" + DATE_PATTERN_WITH_SECONDS + "}-%i.txt" + compressionSuffix,
158                 sizeThreshold, currentTime, 0);
159 
160         for (int i = runLength; i < runLength * 2; i++) {
161             incCurrentTime(100);
162             tbrp2.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
163             String msg = prefix + i;
164             rfa2.doAppend(msg);
165             addExpectedFileNamedIfItsTime(randomOutputDir, testId, msg, compressionSuffix);
166         }
167     }
168 
169     static final boolean FIRST_PHASE_ONLY = false;
170     static final boolean WITH_SECOND_PHASE = true;
171     static final String DEFAULT_COMPRESSION_SUFFIX = "";
172 
173     @Test
174     public void noCompression_FileSet_NoRestart_1() throws InterruptedException, ExecutionException, IOException {
175         generic("test1", this::testId2FileName, FIRST_PHASE_ONLY, DEFAULT_COMPRESSION_SUFFIX);
176     }
177 
178     @Test
179     public void noCompression_FileBlank_NoRestart_2() throws Exception {
180         generic("test2", this::nullFileName, FIRST_PHASE_ONLY, DEFAULT_COMPRESSION_SUFFIX);
181     }
182 
183     @Test
184     public void noCompression_FileBlank_WithStopStart_3() throws Exception {
185         generic("test3", this::nullFileName, WITH_SECOND_PHASE, DEFAULT_COMPRESSION_SUFFIX);
186     }
187 
188     @Test
189     public void noCompression_FileSet_WithStopStart_4() throws Exception {
190         generic("test4", this::testId2FileName, WITH_SECOND_PHASE, DEFAULT_COMPRESSION_SUFFIX);
191     }
192 
193     @Test
194     public void withGZCompression_FileSet_NoRestart_5() throws Exception {
195         generic("test5", this::testId2FileName, FIRST_PHASE_ONLY, ".gz");
196     }
197 
198     @Test
199     public void withGZCompression_FileBlank_NoRestart_6() throws Exception {
200         generic("test6", this::nullFileName, FIRST_PHASE_ONLY, ".gz");
201     }
202 
203     @Test
204     public void withZipCompression_FileSet_NoRestart_7() throws Exception {
205         generic("test7", this::testId2FileName, FIRST_PHASE_ONLY, ".zip");
206         List<String> zipFiles = filterElementsInListBySuffix(".zip");
207         checkZipEntryMatchesZipFilename(zipFiles);
208     }
209 
210     @Test
211     public void checkMissingIntToken() {
212         String stem = "toto.log";
213         String testId = "checkMissingIntToken";
214         String compressionSuffix = "gz";
215 
216         String file = (stem != null) ? randomOutputDir + stem : null;
217         initRollingFileAppender(rfa1, file);
218         sizeThreshold = 300;
219         initPolicies(rfa1, tbrp1,
220                 randomOutputDir + testId + "-%d{" + DATE_PATTERN_WITH_SECONDS + "}.txt" + compressionSuffix,
221                 sizeThreshold, currentTime, 0);
222 
223         // StatusPrinter.print(context);
224         assertFalse(rfa1.isStarted());
225         StatusChecker checker = new StatusChecker(context);
226         checker.assertContainsMatch("Missing integer token");
227     }
228 
229     @Test
230     public void checkDateCollision() {
231         String stem = "toto.log";
232         String testId = "checkDateCollision";
233         String compressionSuffix = "gz";
234 
235         String file = (stem != null) ? randomOutputDir + stem : null;
236         initRollingFileAppender(rfa1, file);
237         sizeThreshold = 300;
238         initPolicies(rfa1, tbrp1, randomOutputDir + testId + "-%d{EE}.txt" + compressionSuffix, sizeThreshold,
239                 currentTime, 0);
240 
241         // StatusPrinter.print(context);
242         assertFalse(rfa1.isStarted());
243         StatusChecker checker = new StatusChecker(context);
244         checker.assertContainsMatch("The date format in FileNamePattern");
245     }
246 
247     // @Test
248     // public void testHistoryAsFileCount() throws IOException {
249     // String testId = "testHistoryAsFileCount";
250     // int maxHistory = 10;
251     // initRollingFileAppender(rfa1, randomOutputDir + "~" + testId);
252     // sizeThreshold = 50;
253     // System.out.println("testHistoryAsFileCount started on "+new
254     // Date(currentTime));
255     // initPolicies(rfa1, tbrp1, randomOutputDir + testId + "-%d{" +
256     // DATE_PATTERN_WITH_SECONDS + "}-%i.txt",
257     // sizeThreshold, currentTime, 0, maxHistory, true);
258     //
259     // incCurrentTime(100);
260     // tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
261     // int runLength = 1000;
262     //
263     // for (int i = 0; i < runLength; i++) {
264     // String msg = "" + i;
265     // rfa1.doAppend(msg);
266     // incCurrentTime(20);
267     // tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
268     // add(tbrp1.future);
269     // }
270     //
271     // Thread.yield();
272     // // wait for compression to finish
273     // waitForJobsToComplete();
274     //
275     // assertEquals(maxHistory + 1, getFilesInDirectory(randomOutputDir).length);
276     // sortedContentCheck(randomOutputDir, 1000, "", 863);
277     // }
278 }