diff --git a/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java index 8e75998e..0707bfcc 100644 --- a/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java +++ b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java @@ -2,22 +2,23 @@ import com.cronutils.model.Cron; import com.cronutils.model.CronType; -import com.cronutils.model.definition.CronDefinition; import com.cronutils.model.definition.CronDefinitionBuilder; import com.cronutils.parser.CronParser; + import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import org.joda.time.DateTimeZone; +import org.joda.time.Duration; import org.joda.time.Interval; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - import java.text.SimpleDateFormat; +import static org.junit.Assert.*; + /* * Copyright 2015 jmrozanec * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,24 +32,24 @@ * limitations under the License. */ public class ExecutionTimeQuartzIntegrationTest { - private CronParser quartzCronParser; + private CronParser parser; private static final String EVERY_SECOND = "* * * * * ? *"; @Before public void setUp(){ - quartzCronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); + parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); } @Test public void testForCron() throws Exception { - assertEquals(ExecutionTime.class, ExecutionTime.forCron(quartzCronParser.parse(EVERY_SECOND)).getClass()); + assertEquals(ExecutionTime.class, ExecutionTime.forCron(parser.parse(EVERY_SECOND)).getClass()); } @Test public void testNextExecutionEverySecond() throws Exception { DateTime now = truncateToSeconds(DateTime.now()); DateTime expected = truncateToSeconds(now.plusSeconds(1)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(EVERY_SECOND)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND)); assertEquals(expected, executionTime.nextExecution(now)); } @@ -56,7 +57,7 @@ public void testNextExecutionEverySecond() throws Exception { public void testTimeToNextExecution() throws Exception { DateTime now = truncateToSeconds(DateTime.now()); DateTime expected = truncateToSeconds(now.plusSeconds(1)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(EVERY_SECOND)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND)); assertEquals(new Interval(now, expected).toDuration(), executionTime.timeToNextExecution(now)); } @@ -64,7 +65,7 @@ public void testTimeToNextExecution() throws Exception { public void testLastExecution() throws Exception { DateTime now = truncateToSeconds(DateTime.now()); DateTime expected = truncateToSeconds(now.minusSeconds(1)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(EVERY_SECOND)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND)); assertEquals(expected, executionTime.lastExecution(now)); } @@ -72,7 +73,7 @@ public void testLastExecution() throws Exception { public void testTimeFromLastExecution() throws Exception { DateTime now = truncateToSeconds(DateTime.now()); DateTime expected = truncateToSeconds(now.minusSeconds(1)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(EVERY_SECOND)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND)); assertEquals(new Interval(expected, now).toDuration(), executionTime.timeFromLastExecution(now)); } @@ -84,10 +85,8 @@ public void testTimeFromLastExecution() throws Exception { */ @Test public void testDoesNotIgnoreMonthOrDayOfWeek(){ - CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ); - CronParser cronParser = new CronParser(cronDefinition); //seconds, minutes, hours, dayOfMonth, month, dayOfWeek - ExecutionTime executionTime = ExecutionTime.forCron(cronParser.parse("0 11 11 11 11 ?")); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 11 11 11 11 ?")); DateTime now = new DateTime(2015, 4, 15, 0, 0, 0); DateTime whenToExecuteNext = executionTime.nextExecution(now); assertEquals(2015, whenToExecuteNext.getYear()); @@ -107,7 +106,7 @@ public void testHourlyIntervalTimeFromLastExecution() throws Exception { DateTime now = DateTime.now(); DateTime previousHour = now.minusHours(1); String quartzCronExpression = String.format("0 0 %s * * ?", previousHour.getHourOfDay()); - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(quartzCronExpression)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(quartzCronExpression)); assertTrue(executionTime.timeFromLastExecution(now).getStandardMinutes() <= 120); } @@ -121,7 +120,7 @@ public void testHourlyIntervalTimeFromLastExecution() throws Exception { @Test public void testShiftTo24thHour() { String expression = "0/1 * * 1/1 * ? *"; // every second every day - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(expression)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(expression)); DateTime now = new DateTime().withTime(23, 59, 59, 0); DateTime expected = now.plusSeconds(1); @@ -139,7 +138,7 @@ public void testShiftTo24thHour() { @Test public void testShiftTo32ndDay() { String expression = "0/1 * * 1/1 * ? *"; // every second every day - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(expression)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(expression)); DateTime now = new DateTime(2015, 1, 31, 23, 59, 59, 0); DateTime expected = now.plusSeconds(1); @@ -153,13 +152,8 @@ public void testShiftTo32ndDay() { */ @Test public void testTimeShiftingProperlyDone() throws Exception { - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse("0 0/10 22 ? * *")); - DateTime nextExecution = - executionTime.nextExecution( - DateTime.now() - .withHourOfDay(15) - .withMinuteOfHour(27) - ); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0/10 22 ? * *")); + DateTime nextExecution = executionTime.nextExecution(DateTime.now().withHourOfDay(15).withMinuteOfHour(27)); assertEquals(22, nextExecution.getHourOfDay()); assertEquals(0, nextExecution.getMinuteOfHour()); } @@ -169,7 +163,7 @@ public void testTimeShiftingProperlyDone() throws Exception { */ @Test public void testMonthRangeExecutionTime(){ - ExecutionTime.forCron(quartzCronParser.parse("0 0 0 * JUL-AUG ? *")); + ExecutionTime.forCron(parser.parse("0 0 0 * JUL-AUG ? *")); } /** @@ -178,7 +172,6 @@ public void testMonthRangeExecutionTime(){ @Test public void testSaturdayExecutionTime(){ DateTime now = DateTime.now(); - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * 6")); DateTime last = executionTime.lastExecution(now); DateTime next = executionTime.nextExecution(now); @@ -191,7 +184,6 @@ public void testSaturdayExecutionTime(){ @Test public void testWeekdayExecutionTime(){ DateTime now = DateTime.now(); - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * *")); DateTime last = executionTime.lastExecution(now); DateTime next = executionTime.nextExecution(now); @@ -203,8 +195,7 @@ public void testWeekdayExecutionTime(){ */ @Test public void testExecutionTimeForRanges(){ - final CronParser quartzParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzParser.parse("* 10-20 * * * ? 2099")); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("* 10-20 * * * ? 2099")); DateTime scanTime = DateTime.parse("2016-02-29T11:00:00.000-06:00"); DateTime nextTime = executionTime.nextExecution(scanTime); assertNotNull(nextTime); @@ -216,8 +207,7 @@ public void testExecutionTimeForRanges(){ */ @Test public void testLastExecutionTimeForFixedMonth(){ - final CronParser quartzParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzParser.parse("0 30 12 1 9 ? 2010")); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 30 12 1 9 ? 2010")); DateTime scanTime = DateTime.parse("2016-01-08T11:00:00.000-06:00"); DateTime lastTime = executionTime.lastExecution(scanTime); assertNotNull(lastTime); @@ -230,9 +220,7 @@ public void testLastExecutionTimeForFixedMonth(){ @Test public void testNextExecutionRightDoWForFixedMonth(){ //cron format: s,m,H,DoM,M,DoW,Y - final CronType cronType = CronType.QUARTZ; - final CronParser quartzParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(cronType)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzParser.parse("0 * * ? 5 1 *")); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 * * ? 5 1 *")); DateTime scanTime = DateTime.parse("2016-03-06T20:17:28.000-03:00"); DateTime nextTime = executionTime.nextExecution(scanTime); assertNotNull(nextTime); @@ -245,9 +233,7 @@ public void testNextExecutionRightDoWForFixedMonth(){ @Test public void testNextExecutionRightDoWForFixedYear(){ //cron format: s,m,H,DoM,M,DoW,Y - final CronType cronType = CronType.QUARTZ; - final CronParser quartzParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(cronType)); - ExecutionTime executionTime = ExecutionTime.forCron(quartzParser.parse("0 * * ? * 1 2099")); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 * * ? * 1 2099")); DateTime scanTime = DateTime.parse("2016-03-06T20:17:28.000-03:00"); DateTime nextTime = executionTime.nextExecution(scanTime); assertNotNull(nextTime); @@ -259,8 +245,7 @@ public void testNextExecutionRightDoWForFixedYear(){ */ @Test(expected = IllegalArgumentException.class) public void testIllegalQuestionMarkValue(){ - final CronParser quartzParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); - ExecutionTime.forCron(quartzParser.parse("0 0 12 1W ? *"));//s,m,H,DoM,M,DoW + ExecutionTime.forCron(parser.parse("0 0 12 1W ? *"));//s,m,H,DoM,M,DoW } /** @@ -271,7 +256,6 @@ public void testIllegalQuestionMarkValue(){ @Test//TODO public void testNextExecutionProducingInvalidPrintln(){ String cronText = "0 0/15 * * * ?"; - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); Cron cron = parser.parse(cronText); final ExecutionTime executionTime = ExecutionTime.forCron(cron); } @@ -282,7 +266,6 @@ public void testNextExecutionProducingInvalidPrintln(){ @Test public void testNextExecutionProducingInvalidValues(){ String cronText = "0 0 18 ? * MON"; - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); Cron cron = parser.parse(cronText); final ExecutionTime executionTime = ExecutionTime.forCron(cron); DateTime now = DateTime.parse("2016-03-18T19:02:51.424+09:00"); @@ -304,7 +287,7 @@ public void testNextExecutionProducingInvalidValues(){ @Test public void testMultipleMinuteIntervalTimeFromLastExecution() throws Exception { String expression = "* 8-10,23-25,38-40,53-55 * * * ? *"; // every second for intervals of minutes - ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(expression)); + ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(expression)); assertEquals(301, executionTime.timeFromLastExecution(new DateTime().withTime(3, 1, 0, 0)).getStandardSeconds()); assertEquals(1, executionTime.timeFromLastExecution(new DateTime().withTime(13, 8, 4, 0)).getStandardSeconds()); @@ -321,32 +304,29 @@ public void testMultipleMinuteIntervalTimeFromLastExecution() throws Exception { */ @Test public void testMultipleMinuteIntervalMatch() throws Exception { - CronParser cronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(com.cronutils.model.CronType.QUARTZ)); - - assertEquals(ExecutionTime.forCron(cronParser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 20, 0, 0)), false); - assertEquals(ExecutionTime.forCron(cronParser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 21, 0, 0)), true); - assertEquals(ExecutionTime.forCron(cronParser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 0, 0, 0)), true); - assertEquals(ExecutionTime.forCron(cronParser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 4, 0, 0)), true); - assertEquals(ExecutionTime.forCron(cronParser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 5, 0, 0)), false); + assertEquals(ExecutionTime.forCron(parser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 20, 0, 0)), false); + assertEquals(ExecutionTime.forCron(parser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 21, 0, 0)), true); + assertEquals(ExecutionTime.forCron(parser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 0, 0, 0)), true); + assertEquals(ExecutionTime.forCron(parser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 4, 0, 0)), true); + assertEquals(ExecutionTime.forCron(parser.parse("* * 21-23,0-4 * * ?")).isMatch(new DateTime(2014, 9, 20, 5, 0, 0)), false); } - + @Test public void testDayLightSavingsSwitch() { try { // every 2 minutes String expression = "* 0/2 * * * ?"; - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); Cron cron = parser.parse(expression); // SIMULATE SCHEDULE JUST PRIOR TO DST DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy MM dd HH:mm:ss").withZone(DateTimeZone.forID("America/Denver")); DateTime prevRun = new DateTime(formatter.parseDateTime("2016 03 13 01:59:59")); - ExecutionTime executionTime = ExecutionTime.forCron(cron); + ExecutionTime executionTime = ExecutionTime.forCron(cron); DateTime nextRun = executionTime.nextExecution(prevRun); // Assert we got 3:00am assertEquals("Incorrect Hour", 3, nextRun.getHourOfDay()); - assertEquals("Incorrect Minute", 0, nextRun.getMinuteOfHour()); + assertEquals("Incorrect Minute", 0, nextRun.getMinuteOfHour()); // SIMULATE SCHEDULE POST DST - simulate a schedule after DST 3:01 with the same cron, expect 3:02 nextRun = nextRun.plusMinutes(1); @@ -372,44 +352,62 @@ public void testDayLightSavingsSwitch() { public void testCronWithFirstWorkDayOfWeek() { try { String cronText = "0 0 12 1W * ? *"; - CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); Cron cron = parser.parse(cronText); DateTime dt = new DateTime(new SimpleDateFormat("yyyy MM dd HH:mm:ss").parseObject("2016 03 29 00:00:59")); - ExecutionTime executionTime = ExecutionTime.forCron(cron); + ExecutionTime executionTime = ExecutionTime.forCron(cron); DateTime nextRun = executionTime.nextExecution(dt); - assertEquals("incorrect Day", nextRun.getDayOfMonth(), 1); // should be April 1st (Friday) + assertEquals("incorrect Day", nextRun.getDayOfMonth(), 1); // should be April 1st (Friday) } - catch(Exception e) { + catch(Exception e) { fail("Exception Received: "+e.getMessage()); - } + } } /** - * Issue #81: MON-SUN flags are not mapped correctly to 1-7 number representations
 + * Issue #81: MON-SUN flags are not mapped correctly to 1-7 number representations * Fixed by adding shifting function when changing monday position. */ @Test public void testDayOfWeekMapping() { - CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ); - CronParser parser = new CronParser(cronDefinition); DateTime fridayMorning = new DateTime(2016, 4, 22, 0, 0, 0, DateTimeZone.UTC); ExecutionTime numberExec = ExecutionTime.forCron(parser.parse("0 0 12 ? * 2,3,4,5,6 *")); ExecutionTime nameExec = ExecutionTime.forCron(parser.parse("0 0 12 ? * MON,TUE,WED,THU,FRI *")); - assertEquals("same generated dates", - numberExec.nextExecution(fridayMorning), - nameExec.nextExecution(fridayMorning) - ); + assertEquals("same generated dates", numberExec.nextExecution(fridayMorning), + nameExec.nextExecution(fridayMorning)); + } + + /** + * Issue #91: Calculating the minimum interval for a cron expression. + */ + @Test + public void testMinimumInterval() { + Duration s1 = Duration.standardSeconds(1); + assertEquals(getMinimumInterval("* * * * * ?"), s1); + assertEquals("Should ignore whitespace", getMinimumInterval("* * * * * ?"), s1); + assertEquals(getMinimumInterval("0/1 * * * * ?"), s1); + assertEquals(getMinimumInterval("*/1 * * * * ?"), s1); + + Duration s60 = Duration.standardSeconds(60); + assertEquals(getMinimumInterval("0 * * * * ?"), s60); + assertEquals(getMinimumInterval("0 */1 * * * ?"), s60); + + assertEquals(getMinimumInterval("0 */5 * * * ?"), Duration.standardSeconds(300)); + assertEquals(getMinimumInterval("0 0 * * * ?"), Duration.standardSeconds(3600)); + assertEquals(getMinimumInterval("0 0 */3 * * ?"), Duration.standardSeconds(10800)); + assertEquals(getMinimumInterval("0 0 0 * * ?"), Duration.standardSeconds(86400)); + } + + private Duration getMinimumInterval(String quartzPattern) { + ExecutionTime et = ExecutionTime.forCron(parser.parse(quartzPattern)); + DateTime coolDay = new DateTime(2016, 1, 1, 0, 0, 0); + // Find next execution time #1 + DateTime t1 = et.nextExecution(coolDay); + // Find next execution time #2 right after #1, the interval between them is minimum + return et.timeToNextExecution(t1); } private DateTime truncateToSeconds(DateTime dateTime){ - return new DateTime( - dateTime.getYear(), - dateTime.getMonthOfYear(), - dateTime.getDayOfMonth(), - dateTime.getHourOfDay(), - dateTime.getMinuteOfHour(), - dateTime.getSecondOfMinute() - ); + return dateTime.secondOfMinute().roundFloorCopy(); } } \ No newline at end of file diff --git a/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java b/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java index 877b30b1..77b6d85f 100644 --- a/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java +++ b/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java @@ -6,18 +6,18 @@ import com.cronutils.model.definition.CronDefinition; import com.cronutils.model.definition.CronDefinitionBuilder; import com.cronutils.model.time.ExecutionTime; + import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import java.util.Locale; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /* * Copyright 2015 jmrozanec * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,6 +36,9 @@ public class CronParserQuartzIntegrationTest { private CronParser parser; + @Rule + public ExpectedException thrown = ExpectedException.none(); + @Before public void setUp() throws Exception { parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); @@ -215,14 +218,9 @@ public void testIntervalMinutes() { */ @Test public void testRegressionDifferentMessageForException(){ - boolean asserted = false; - try{ - ExecutionTime.forCron(parser.parse("* * * * $ ?")); - }catch (IllegalArgumentException e){ - assertEquals("Invalid chars in expression! Expression: $ Invalid chars: $", e.getMessage()); - asserted = true; - } - assertTrue(asserted); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Invalid chars in expression! Expression: $ Invalid chars: $"); + ExecutionTime.forCron(parser.parse("* * * * $ ?")); } /** @@ -230,13 +228,24 @@ public void testRegressionDifferentMessageForException(){ */ @Test public void testReportedErrorContainsSameExpressionAsProvided(){ - boolean asserted = false; - try{ - ExecutionTime.forCron(parser.parse("0/1 * * * * *")); - }catch (IllegalArgumentException e){ - assertEquals("Invalid cron expression: 0 * * * * *. Both, a day-of-week AND a day-of-month parameter, are not supported.", e.getMessage()); - asserted = true; - } - assertTrue(asserted); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage( + "Invalid cron expression: 0 * * * * *. Both, a day-of-week AND a day-of-month parameter, are not supported."); + ExecutionTime.forCron(parser.parse("0/1 * * * * *")); + } + + @Test + public void testErrorAbout2Parts(){ + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Cron expression contains 2 parts but we expect one of [6, 7]"); + ExecutionTime.forCron(parser.parse("* *")); } + + @Test + public void testErrorAboutMissingSteps(){ + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Missing steps for expression: */"); + ExecutionTime.forCron(parser.parse("*/ * * * * ?")); + } + }