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.FileOutputStream;
18  import java.io.IOException;
19  import java.util.function.UnaryOperator;
20  
21  import org.junit.jupiter.api.AfterEach;
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.Test;
24  
25  import ch.qos.logback.core.encoder.EchoEncoder;
26  import ch.qos.logback.core.rolling.testUtil.ScaffoldingForRollingTests;
27  import ch.qos.logback.core.testUtil.EnvUtilForTests;
28  import ch.qos.logback.core.util.StatusPrinter;
29  
30  /**
31   * A rather exhaustive set of tests. Tests include leaving the file option
32   * blank, or setting it, with and without compression, and tests with or without
33   * stopping/restarting the RollingFileAppender.
34   * <p>
35   * The regression tests log a few times using a RollingFileAppender. Then, they
36   * predict the names of the files which should be generated and compare them
37   * with witness files.
38   * <p>
39   * 
40   * <pre>
41   *                Compression     file option    Stop/Restart
42   *     Test1      NO              BLANK           NO
43   *     Test2      YES             BLANK           NO
44   *     Test3      NO              BLANK           YES
45   *     Test4      NO              SET             YES
46   *     Test5      NO              SET             NO
47   *     Test6      YES             SET             NO
48   * </pre>
49   *
50   * @author Ceki G&uuml;lc&uuml;
51   */
52  public class TimeBasedRollingTest extends ScaffoldingForRollingTests {
53  
54      static final int NO_RESTART = 0;
55      static final int WITH_RESTART = 1;
56      static final int WITH_RESTART_AND_LONG_WAIT = 2000;
57  
58      static final boolean FILE_OPTION_SET = true;
59      static final boolean FILE_OPTION_BLANK = false;
60  
61      RollingFileAppender<Object> rfa1 = new RollingFileAppender<Object>();
62      TimeBasedRollingPolicy<Object> tbrp1 = new TimeBasedRollingPolicy<Object>();
63  
64      RollingFileAppender<Object> rfa2 = new RollingFileAppender<Object>();
65      TimeBasedRollingPolicy<Object> tbrp2 = new TimeBasedRollingPolicy<Object>();
66  
67      EchoEncoder<Object> encoder = new EchoEncoder<Object>();
68  
69      RolloverChecker rolloverChecker;
70  
71      @BeforeEach
72      @Override
73      public void setUp() {
74          super.setUp();
75      }
76  
77      @AfterEach
78      public void tearDown() {
79      }
80  
81      void initRFA(RollingFileAppender<Object> rfa, String filename) {
82          rfa.setContext(context);
83          rfa.setEncoder(encoder);
84          if (filename != null) {
85              rfa.setFile(filename);
86          }
87      }
88  
89      void initTRBP(RollingFileAppender<Object> rfa, TimeBasedRollingPolicy<Object> tbrp, String filenamePattern,
90              long givenTime) {
91          tbrp.setContext(context);
92          tbrp.setFileNamePattern(filenamePattern);
93          tbrp.setParent(rfa);
94          tbrp.timeBasedFileNamingAndTriggeringPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<Object>();
95          tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(givenTime);
96          rfa.setRollingPolicy(tbrp);
97          tbrp.start();
98          rfa.start();
99      }
100 
101     void genericTest(String testId, String patternPrefix, String compressionSuffix,
102             UnaryOperator<String> filenameFunction, int waitDuration) throws IOException {
103 
104         String fileName = filenameFunction.apply(testId);
105         // String fileName = fileOptionIsSet ? testId2FileName(testId) : null;
106 
107         initRFA(rfa1, fileName);
108 
109         String fileNamePatternStr = randomOutputDir + patternPrefix + "-%d{" + DATE_PATTERN_WITH_SECONDS + "}"
110                 + compressionSuffix;
111 
112         initTRBP(rfa1, tbrp1, fileNamePatternStr, currentTime);
113 
114         // compute the current filename
115         addExpectedFileName_ByDate(fileNamePatternStr, getMillisOfCurrentPeriodsStart());
116 
117         incCurrentTime(1100);
118         tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
119 
120         for (int i = 0; i < 3; i++) {
121             rfa1.doAppend("Hello---" + i);
122             addExpectedFileNamedIfItsTime_ByDate(fileNamePatternStr);
123             incCurrentTime(500);
124             tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
125             add(tbrp1.compressionFuture);
126             add(tbrp1.cleanUpFuture);
127         }
128         rfa1.stop();
129         waitForJobsToComplete();
130 
131         if (waitDuration != NO_RESTART) {
132             doRestart(testId, patternPrefix, filenameFunction, waitDuration);
133         }
134         waitForJobsToComplete();
135 
136         massageExpectedFilesToCorresponToCurrentTarget(testId, filenameFunction);
137         // StatusPrinter.print(context);
138         rolloverChecker.check(expectedFilenameList);
139     }
140 
141     void defaultTest(String testId, String patternPrefix, String compressionSuffix,
142             UnaryOperator<String> filenameFunction, int waitDuration) throws IOException {
143         boolean withCompression = compressionSuffix.length() > 0;
144         rolloverChecker = new DefaultRolloverChecker(testId, withCompression, compressionSuffix);
145         genericTest(testId, patternPrefix, compressionSuffix, filenameFunction, waitDuration);
146     }
147 
148     void doRestart(String testId, String patternPart, UnaryOperator<String> filenameFunction, int waitDuration) {
149         // change the timestamp of the currently actively file
150         File activeFile = new File(rfa1.getFile());
151         activeFile.setLastModified(currentTime);
152 
153         incCurrentTime(waitDuration);
154 
155         String filePatternStr = randomOutputDir + patternPart + "-%d{" + DATE_PATTERN_WITH_SECONDS + "}";
156 
157         String fileName = filenameFunction.apply(testId);
158         initRFA(rfa2, fileName);
159         initTRBP(rfa2, tbrp2, filePatternStr, currentTime);
160         for (int i = 0; i < 3; i++) {
161             rfa2.doAppend("World---" + i);
162             addExpectedFileNamedIfItsTime_ByDate(filePatternStr);
163             incCurrentTime(100);
164             tbrp2.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
165             add(tbrp2.compressionFuture);
166             add(tbrp1.cleanUpFuture);
167         }
168         rfa2.stop();
169     }
170 
171     @Test
172     public void noCompression_FileBlank_NoRestart_1() throws IOException {
173         defaultTest("test1", "test1", "", this::nullFileName, NO_RESTART);
174     }
175 
176     @Test
177     public void withCompression_FileBlank_NoRestart_2() throws IOException {
178         defaultTest("test2", "test2", ".gz", this::nullFileName, NO_RESTART);
179     }
180 
181     @Test
182     public void noCompression_FileBlank_StopRestart_3() throws IOException {
183         defaultTest("test3", "test3", "", this::nullFileName, WITH_RESTART);
184     }
185 
186     @Test
187     public void noCompression_FileSet_StopRestart_4() throws IOException {
188         defaultTest("test4", "test4", "", this::testId2FileName, WITH_RESTART);
189     }
190 
191     @Test
192     public void noCompression_FileSet_StopRestart_WithLongWait_4B() throws IOException {
193         defaultTest("test4B", "test4B", "", this::testId2FileName, WITH_RESTART_AND_LONG_WAIT);
194     }
195 
196     @Test
197     public void noCompression_FileSet_NoRestart_5() throws IOException {
198         defaultTest("test5", "test5", "", this::testId2FileName, NO_RESTART);
199     }
200 
201     @Test
202     public void withCompression_FileSet_NoRestart_6() throws IOException {
203         defaultTest("test6", "test6", ".gz", this::testId2FileName, NO_RESTART);
204     }
205 
206     // LOGBACK-168
207     @Test
208     public void withMissingTargetDirWithCompression() throws IOException {
209         defaultTest("test7", "%d{yyyy-MM-dd, aux}/test7", ".gz", this::testId2FileName, NO_RESTART);
210     }
211 
212     @Test
213     public void withMissingTargetDirWithZipCompression() throws IOException {
214         defaultTest("test8", "%d{yyyy-MM-dd, aux}/test8", ".zip", this::testId2FileName, NO_RESTART);
215     }
216 
217     @Test
218     public void failed_rename() throws IOException {
219         if (!EnvUtilForTests.isWindows())
220             return;
221 
222         String testId = "failed_rename";
223         FileOutputStream fos = null;
224         try {
225             String fileName = testId2FileName(testId);
226             File file = new File(fileName);
227             file.getParentFile().mkdirs();
228 
229             fos = new FileOutputStream(fileName);
230 
231             rolloverChecker = new ZRolloverChecker(testId);
232             genericTest(testId, "failed_rename", "", this::testId2FileName, NO_RESTART);
233             rolloverChecker.check(expectedFilenameList);
234 
235         } finally {
236             StatusPrinter.print(context);
237             if (fos != null)
238                 fos.close();
239         }
240     }
241 
242 //    @Test
243 //    public void failed_rename2() throws IOException {
244 //
245 //        String testId = "failed_rename";
246 //        try {
247 //            String fileName = testId2FileName(testId);
248 //
249 //            
250 //            rolloverChecker = new ZRolloverChecker(testId);
251 //            genericTest(testId, "test10", ".gz", this::testId2FileName, NO_RESTART);
252 //            rolloverChecker.check(expectedFilenameList);
253 //
254 //        } finally {
255 //            StatusPrinter.print(context);
256 //
257 //        }
258 //    }
259 
260 }