/*
* Copyright 2014 LinkedIn Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package azkaban.trigger;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import azkaban.trigger.builtin.BasicTimeChecker;
import azkaban.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
import org.joda.time.ReadablePeriod;
import org.junit.Test;
public class BasicTimeCheckerTest {
private Condition getCondition(final BasicTimeChecker timeChecker) {
final Map<String, ConditionChecker> checkers =
new HashMap<>();
checkers.put(timeChecker.getId(), timeChecker);
final String expr = timeChecker.getId() + ".eval()";
return new Condition(checkers, expr);
}
/**
* This test manipulates global states (time) in org.joda.time.DateTimeUtils . Thus this test can
* run in parallel with tests that do the same.
*/
@Test
public void periodTimerTest() {
// get a new timechecker, start from now, repeat every minute. should
// evaluate to false now, and true a minute later.
final long baseTimeInMilliSeconds = 1000;
final ReadablePeriod period = Utils.parsePeriodString("10s");
DateTimeUtils.setCurrentMillisFixed(baseTimeInMilliSeconds);
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", baseTimeInMilliSeconds,
DateTimeZone.UTC, true, true, period, null);
final Condition cond = getCondition(timeChecker);
assertFalse(cond.isMet());
DateTimeUtils.setCurrentMillisFixed(baseTimeInMilliSeconds + 11 * 1000);
assertTrue(cond.isMet());
cond.resetCheckers();
assertFalse(cond.isMet());
DateTimeUtils.setCurrentMillisFixed(baseTimeInMilliSeconds + 22 * 1000);
assertTrue(cond.isMet());
DateTimeUtils.setCurrentMillisSystem();
}
/**
* Test Base Cron Functionality.
*/
@Test
public void testQuartzCurrentZone() {
final DateTime now = DateTime.now();
final String cronExpression = "0 0 0 31 12 ? 2050";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", now.getMillis(),
now.getZone(), true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
// 2556086400000L represent for "2050-12-31T00:00:00.000-08:00"
final DateTime year2050 = new DateTime(2050, 12, 31, 0, 0, 0, now.getZone());
assertTrue(cond.getNextCheckTime() == year2050.getMillis());
}
/**
* Test when PST-->PDT happens in 2020. -8:00 -> -7:00 See details why confusion happens during
* this change: https://en.wikipedia.org/wiki/Pacific_Time_Zone
*
* This test demonstrates that if the cron is under UTC settings, When daylight saving change
* occurs, 2:30 will be changed to 3:30 at that day.
*/
@Test
public void testPSTtoPDTunderUTC() {
final DateTime now = DateTime.now();
// 10:30 UTC == 2:30 PST
final String cronExpression = "0 30 10 8 3 ? 2020";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", now.getMillis(),
DateTimeZone.UTC, true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
final DateTime spring2020UTC = new DateTime(2020, 3, 8, 10, 30, 0, DateTimeZone.UTC);
final DateTime spring2020PDT = new DateTime(2020, 3, 8, 3, 30, 0,
DateTimeZone.forID("America/Los_Angeles"));
assertTrue(cond.getNextCheckTime() == spring2020UTC.getMillis());
assertTrue(cond.getNextCheckTime() == spring2020PDT.getMillis());
}
/**
* Test when PST-->PDT happens in 2020. -8:00 -> -7:00 See details why confusion happens during
* this change: https://en.wikipedia.org/wiki/Pacific_Time_Zone
*
* This test demonstrates that 2:30 AM will not happen during the daylight saving day on Cron
* settings under PDT/PST. Since we let the cron triggered both at March 8th, and 9th, it will
* execute at March 9th.
*/
@Test
public void testPSTtoPDTdst2() {
final DateTime now = DateTime.now();
final String cronExpression = "0 30 2 8,9 3 ? 2020";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecker_1", now.getMillis(),
DateTimeZone.forID("America/Los_Angeles"), true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
final DateTime aTime = new DateTime(2020, 3, 9, 2, 30, 0,
DateTimeZone.forID("America/Los_Angeles"));
assertTrue(cond.getNextCheckTime() == aTime.getMillis());
}
/**
* Test when PDT-->PST happens in 2020. -7:00 -> -8:00 See details why confusion happens during
* this change: https://en.wikipedia.org/wiki/Pacific_Time_Zone
*
* This test cronDayLightPacificWinter1 is in order to compare against the
* cronDayLightPacificWinter2.
*
* In this Test, we let job run at 1:00 at Nov.1st, 2020. We know that we will have two 1:00 at
* that day. The test shows that the first 1:00 is skipped at that day. Schedule will still be
* executed once on that day.
*/
@Test
public void testPDTtoPSTdst1() {
final DateTime now = DateTime.now();
// 9:00 UTC == 1:00 PST (difference is 8 hours)
final String cronExpression = "0 0 1 1,2 11 ? 2020";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", now.getMillis(),
DateTimeZone.forID("America/Los_Angeles"), true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
final DateTime winter2020 = new DateTime(2020, 11, 1, 9, 0, 0, DateTimeZone.UTC);
final DateTime winter2020_2 = new DateTime(2020, 11, 1, 1, 0, 0,
DateTimeZone.forID("America/Los_Angeles"));
final DateTime winter2020_3 = new DateTime(2020, 11, 1, 2, 0, 0,
DateTimeZone.forID("America/Los_Angeles"));
assertTrue(cond.getNextCheckTime() == winter2020.getMillis());
// Both 1 and 2 o'clock can not pass the test. Based on milliseconds we got,
// winter2020_2.getMillis() == 11/1/2020, 1:00:00 AM GMT-7:00 DST
// winter2020_3.getMillis() == 11/1/2020, 2:00:00 AM GMT-8:00
// Both time doesn't match the second 1:00 AM
assertFalse(cond.getNextCheckTime() == winter2020_2.getMillis());
assertFalse(cond.getNextCheckTime() == winter2020_3.getMillis());
}
/**
* Test when PDT-->PST happens in 2020. -7:00 -> -8:00 See details why confusion happens during
* this change: https://en.wikipedia.org/wiki/Pacific_Time_Zone
*
* This test cronDayLightPacificWinter2 is in order to be compared against the
* cronDayLightPacificWinter1.
*
* In this Test, we let job run at 0:59 at Nov.1st, 2020. it shows that it is 7:59 UTC The test
* shows 7:59 UTC jump to 9:00 UTC.
*/
@Test
public void testPDTtoPSTdst2() {
final DateTime now = DateTime.now();
// 7:59 UTC == 0:59 PDT (difference is 7 hours)
final String cronExpression = "0 59 0 1,2 11 ? 2020";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", now.getMillis(),
DateTimeZone.forID("America/Los_Angeles"), true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
// 7:59 UTC == 0:59 PDT (difference is 7 hours)
final DateTime winter2020 = new DateTime(2020, 11, 1, 7, 59, 0, DateTimeZone.UTC);
final DateTime winter2020_2 = new DateTime(2020, 11, 1, 0, 59, 0,
DateTimeZone.forID("America/Los_Angeles"));
// Local time remains the same.
assertTrue(cond.getNextCheckTime() == winter2020.getMillis());
assertTrue(cond.getNextCheckTime() == winter2020_2.getMillis());
}
/**
* Test when PDT-->PST happens in 2020. -7:00 -> -8:00 See details why confusion happens during
* this change: https://en.wikipedia.org/wiki/Pacific_Time_Zone
*
* This test is a supplement to cronDayLightPacificWinter1.
*
* Still, we let job run at 1:30 at Nov.1st, 2020. We know that we will have two 1:30 at that day.
* The test shows the 1:30 at that day will be based on PST, not PDT. It means that the first 1:30
* is skipped at that day.
*/
@Test
public void testPDTtoPSTdst3() {
final DateTime now = DateTime.now();
// 9:30 UTC == 1:30 PST (difference is 8 hours)
final String cronExpression = "0 30 1 1,2 11 ? 2020";
final BasicTimeChecker timeChecker =
new BasicTimeChecker("BasicTimeChecket_1", now.getMillis(),
DateTimeZone.forID("America/Los_Angeles"), true, true, null, cronExpression);
System.out.println("getNextCheckTime = " + timeChecker.getNextCheckTime());
final Condition cond = getCondition(timeChecker);
// 9:30 UTC == 1:30 PST (difference is 8 hours)
final DateTime winter2020 = new DateTime(2020, 11, 1, 9, 30, 0, DateTimeZone.UTC);
final DateTime winter2020_2 = new DateTime(2020, 11, 1, 1, 30, 0,
DateTimeZone.forID("America/Los_Angeles"));
final DateTime winter2020_3 = new DateTime(2020, 11, 1, 2, 30, 0,
DateTimeZone.forID("America/Los_Angeles"));
assertTrue(cond.getNextCheckTime() == winter2020.getMillis());
// Both 1:30 and 2:30 can not pass the test.
assertFalse(cond.getNextCheckTime() == winter2020_2.getMillis());
assertFalse(cond.getNextCheckTime() == winter2020_3.getMillis());
}
}