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.helper;
015
016import static org.junit.Assert.assertEquals;
017import static org.junit.Assert.assertFalse;
018import static org.junit.Assert.assertTrue;
019
020import java.util.Date;
021import java.util.Locale;
022import java.util.TimeZone;
023
024import org.junit.After;
025import org.junit.Before;
026import org.junit.Test;
027
028import ch.qos.logback.core.CoreConstants;
029import ch.qos.logback.core.util.EnvUtil;
030
031public class RollingCalendarTest {
032
033  String dailyPattern = "yyyy-MM-dd";
034
035   @Before
036   public void setUp() {
037       
038       // Most surprisingly, in certain environments (e.g. Windows 7), setting the default locale
039       // allows certain tests to pass which otherwise fail.
040       //
041       // These tests are:
042       //
043       //  checkCollisionFreeness("yyyy-WW", false);
044       //  checkCollisionFreeness("yyyy-ww", true);
045       //  checkCollisionFreeness("ww", false);
046       //  {
047       //    RollingCalendar rc = new RollingCalendar("yyyy-ww");
048       //    assertEquals(PeriodicityType.TOP_OF_WEEK, rc.getPeriodicityType());
049       //  }
050       // 
051       
052       Locale oldLocale = Locale.getDefault();
053       Locale.setDefault(oldLocale);
054   }
055
056   @After
057   public void tearDown() {
058   }
059   
060    @Test
061    public void testPeriodicity() {
062        {
063            RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_HH_mm_ss");
064            assertEquals(PeriodicityType.TOP_OF_SECOND, rc.getPeriodicityType());
065        }
066
067        {
068            RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_HH_mm");
069            assertEquals(PeriodicityType.TOP_OF_MINUTE, rc.getPeriodicityType());
070        }
071
072        {
073            RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_HH");
074            assertEquals(PeriodicityType.TOP_OF_HOUR, rc.getPeriodicityType());
075        }
076
077        {
078            RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_hh");
079            assertEquals(PeriodicityType.TOP_OF_HOUR, rc.getPeriodicityType());
080        }
081
082        {
083            RollingCalendar rc = new RollingCalendar("yyyy-MM-dd");
084            assertEquals(PeriodicityType.TOP_OF_DAY, rc.getPeriodicityType());
085        }
086
087        {
088            RollingCalendar rc = new RollingCalendar("yyyy-MM");
089            assertEquals(PeriodicityType.TOP_OF_MONTH, rc.getPeriodicityType());
090        }
091
092        {
093            RollingCalendar rc = new RollingCalendar("yyyy-ww");
094            assertEquals(PeriodicityType.TOP_OF_WEEK, rc.getPeriodicityType());
095        }
096
097        {
098            RollingCalendar rc = new RollingCalendar("yyyy-WW");
099            assertEquals(PeriodicityType.TOP_OF_WEEK, rc.getPeriodicityType());
100        }
101    }
102
103    @Test
104    public void testVaryingNumberOfHourlyPeriods() {
105        RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_HH");
106
107        long MILLIS_IN_HOUR = 3600 * 1000;
108
109        for (int p = 100; p > -100; p--) {
110            long now = 1223325293589L; // Mon Oct 06 22:34:53 CEST 2008
111            Date result = rc.getEndOfNextNthPeriod(new Date(now), p);
112            long expected = now - (now % (MILLIS_IN_HOUR)) + p * MILLIS_IN_HOUR;
113            assertEquals(expected, result.getTime());
114        }
115    }
116
117    @Test
118    public void testVaryingNumberOfDailyPeriods() {
119        RollingCalendar rc = new RollingCalendar("yyyy-MM-dd");
120        final long MILLIS_IN_DAY = 24 * 3600 * 1000;
121
122        for (int p = 20; p > -100; p--) {
123            long now = 1223325293589L; // Mon Oct 06 22:34:53 CEST 2008
124            Date nowDate = new Date(now);
125            Date result = rc.getEndOfNextNthPeriod(nowDate, p);
126            long offset = rc.getTimeZone().getRawOffset() + rc.getTimeZone().getDSTSavings();
127
128            long origin = now - ((now + offset) % (MILLIS_IN_DAY));
129            long expected = origin + p * MILLIS_IN_DAY;
130            assertEquals("p=" + p, expected, result.getTime());
131        }
132    }
133
134    // Wed Mar 23 23:07:05 CET 2016
135    final long WED_2016_03_23_T_230705_CET = 1458770825333L;
136
137    @Test
138    public void testBarrierCrossingComputation() {
139        checkPeriodBarriersCrossed("yyyy-MM-dd'T'HHmmss", WED_2016_03_23_T_230705_CET, WED_2016_03_23_T_230705_CET + 3*CoreConstants.MILLIS_IN_ONE_SECOND, 3);
140        checkPeriodBarriersCrossed("yyyy-MM-dd'T'HHmm", WED_2016_03_23_T_230705_CET, WED_2016_03_23_T_230705_CET + 3*CoreConstants.MILLIS_IN_ONE_MINUTE, 3);
141        checkPeriodBarriersCrossed("yyyy-MM-dd'T'HH", WED_2016_03_23_T_230705_CET, WED_2016_03_23_T_230705_CET + 3*CoreConstants.MILLIS_IN_ONE_HOUR, 3);
142        checkPeriodBarriersCrossed("yyyy-MM-dd", WED_2016_03_23_T_230705_CET, WED_2016_03_23_T_230705_CET + 3*CoreConstants.MILLIS_IN_ONE_DAY, 3);
143    }
144
145    private void checkPeriodBarriersCrossed(String pattern, long start, long end, int count) {
146        RollingCalendar rc = new RollingCalendar(pattern);
147        assertEquals(count, rc.periodBarriersCrossed(start, end));
148    }
149
150    @Test
151    public void testCollisionFreenes() {
152        // hourly
153        checkCollisionFreeness("yyyy-MM-dd hh", false);
154        checkCollisionFreeness("yyyy-MM-dd hh a", true);
155
156        checkCollisionFreeness("yyyy-MM-dd HH", true);
157        checkCollisionFreeness("yyyy-MM-dd kk", true);
158
159        checkCollisionFreeness("yyyy-MM-dd KK", false);
160        checkCollisionFreeness("yyyy-MM-dd KK a", true);
161
162        // daily
163        checkCollisionFreeness("yyyy-MM-dd", true);
164        checkCollisionFreeness("yyyy-dd", false);
165        checkCollisionFreeness("dd", false);
166        checkCollisionFreeness("MM-dd", false);
167
168        checkCollisionFreeness("yyyy-DDD", true);
169        checkCollisionFreeness("DDD", false);
170
171        // 'u' is new to JDK 7
172        if (EnvUtil.isJDK7OrHigher()) {
173            checkCollisionFreeness("yyyy-MM-dd-uu", true);
174            checkCollisionFreeness("yyyy-MM-uu", false);
175        }
176
177        // weekly
178        checkCollisionFreeness("yyyy-MM-WW", true);
179        dumpCurrentLocale(Locale.getDefault());
180        checkCollisionFreeness("yyyy-WW", false);
181        checkCollisionFreeness("yyyy-ww", true);
182        checkCollisionFreeness("ww", false);
183    }
184
185    private void dumpCurrentLocale(Locale locale) {
186       System.out.println("***Current default locale is "+locale);
187        
188    }
189
190    private void checkCollisionFreeness(String pattern, boolean expected) {
191        RollingCalendar rc = new RollingCalendar(pattern);
192        if (expected) {
193            assertTrue(rc.isCollisionFree());
194        } else {
195            assertFalse(rc.isCollisionFree());
196        }
197    }
198
199    @Test
200    public void basicPeriodBarriersCrossed() {
201        RollingCalendar rc = new RollingCalendar(dailyPattern, TimeZone.getTimeZone("CET"), Locale.US);
202        // Thu Jan 26 19:46:58 CET 2017, GMT offset = -1h
203        long start = 1485456418969L;
204        // Fri Jan 27 19:46:58 CET 2017,  GMT offset = -1h
205        long end = start+CoreConstants.MILLIS_IN_ONE_DAY;
206        assertEquals(1, rc.periodBarriersCrossed(start, end));
207    }
208    
209    @Test
210    public void testPeriodBarriersCrossedWhenGoingIntoDaylightSaving() {
211        RollingCalendar rc = new RollingCalendar(dailyPattern, TimeZone.getTimeZone("CET"), Locale.US);
212        // Sun Mar 26 00:02:03 CET  2017, GMT offset = -1h
213        long start = 1490482923333L;
214        // Mon Mar 27 00:02:03 CEST 2017,  GMT offset = -2h
215        long end = 1490565723333L;
216        
217        assertEquals(1, rc.periodBarriersCrossed(start, end));
218    }
219
220    @Test
221    public void testPeriodBarriersCrossedWhenLeavingDaylightSaving() {
222        RollingCalendar rc = new RollingCalendar(dailyPattern, TimeZone.getTimeZone("CET"), Locale.US);
223        // Sun Oct 29 00:02:03 CEST 2017, GMT offset = -2h
224        long start = 1509228123333L;//1490482923333L+217*CoreConstants.MILLIS_IN_ONE_DAY-CoreConstants.MILLIS_IN_ONE_HOUR;
225        // Mon Oct 30 00:02:03 CET  2017,  GMT offset = -1h
226        long end = 1509228123333L+25*CoreConstants.MILLIS_IN_ONE_HOUR;
227        assertEquals(1, rc.periodBarriersCrossed(start, end));
228    }
229    
230    @Test
231    public void testPeriodBarriersCrossedJustBeforeEnteringDaylightSaving() {
232        RollingCalendar rc = new RollingCalendar(dailyPattern, TimeZone.getTimeZone("CET"), Locale.US);
233        // Sun Mar 26 22:18:38 CEST 2017, GMT offset = +2h
234        long start = 1490559518333L;
235        System.out.println(new Date(start));
236        
237        // Mon Mar 27 00:05:18 CEST 2017, GMT offset = +2h
238        long end = 1490565918333L;
239        System.out.println(new Date(end));
240        assertEquals(1, rc.periodBarriersCrossed(start, end));
241        
242        
243    }
244}