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