diff --git a/digdag-core/src/main/java/io/digdag/core/schedule/ScheduleExecutor.java b/digdag-core/src/main/java/io/digdag/core/schedule/ScheduleExecutor.java index 617ac6f8d6..e0f3205f4c 100644 --- a/digdag-core/src/main/java/io/digdag/core/schedule/ScheduleExecutor.java +++ b/digdag-core/src/main/java/io/digdag/core/schedule/ScheduleExecutor.java @@ -55,7 +55,7 @@ public class ScheduleExecutor implements BackgroundExecutor { private static final Logger logger = LoggerFactory.getLogger(ScheduleExecutor.class); - public static final List BUILT_IN_SCHEDULE_PARAMS = Arrays.asList("skip_on_overtime", "skip_delayed_by"); + public static final List BUILT_IN_SCHEDULE_PARAMS = Arrays.asList("skip_on_overtime", "skip_delayed_by", "start", "end"); private final ProjectStoreManager rm; private final ScheduleStoreManager sm; diff --git a/digdag-docs/src/scheduling_workflow.rst b/digdag-docs/src/scheduling_workflow.rst index 924883c49e..80ac1222f6 100644 --- a/digdag-docs/src/scheduling_workflow.rst +++ b/digdag-docs/src/scheduling_workflow.rst @@ -4,7 +4,7 @@ Scheduling workflow .. contents:: :local: -Setting up a schedule: +Setting up a schedule ---------------------------------- To run a workflow periodically, add a ``schedule:`` option to top-level workflow definitions. @@ -135,7 +135,7 @@ It’s this case it’s best to skip the next hour’s workflow session, and ins * Added a ``skip_on_overtime: true | false`` schedule option that can be used to control whether scheduled session execution should be skipped if another session is already running. * Scheduled workflow sessions now have a ``last_executed_session_time`` variable which contains the previously executed session time. It is usually same with ``last_session_time`` but has different value when ``skip_on_overtime: true`` is set or the session is the first execution. -Skipping backfill. +Skipping backfill ------------------ The ``skip_delayed_by`` option enables `backfill `_ command to skip creating sessions delayed by the specified time. When Digdag restarts, sessions of a schedule are automatically created until the next of ``last_session_time``. @@ -162,4 +162,19 @@ If the workflow is executed at 16:02 due to some reason, the session will be ski schedule: cron>: '0 16 * * *' - skip_delayed_by: 1s \ No newline at end of file + skip_delayed_by: 1s + +Set start/end +------------- +The ``start`` and ``end`` options set period of schedule. +The option accepts date format `YYYY-MM-DD`. +When ``start`` is set, the schedule will start on and after ``start``. +When ``end`` is set, the schedule will run until the day (include the day). +When next run time will be after the ``end``, next schedule will be set to `9999-01-01 00:00:00+0000` and never kicked. + +.. note:: + After the schedule ends, if you change ``end`` date to extends the period, the schedule will be resumed from the last session. + It causes multiple session running unexpectedly. + For example, you set `end: 2022-03-31` and current date is `2022-04-15`. + Then you update `end: 2022-04-31`, the sessions between `2022-04-01` and `2022-04-15` will be kicked. + To avoid the case, recommend to set ``skip_delayed_by``. diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/BaseScheduler.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/BaseScheduler.java new file mode 100644 index 0000000000..7825cce037 --- /dev/null +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/BaseScheduler.java @@ -0,0 +1,19 @@ +package io.digdag.standards.scheduler; + +import io.digdag.spi.Scheduler; + +import java.time.Instant; + +public abstract class BaseScheduler implements Scheduler { + Instant SCHEDULE_END = Instant.ofEpochSecond(253370764800L); // 9999-01-01 00:00:00 +0000 + + boolean isScheduleFinished(Instant time) + { + if (time.equals(SCHEDULE_END) || time.isAfter(SCHEDULE_END)) { + return true; + } + else { + return false; + } + } +} diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronScheduler.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronScheduler.java index 77217b4c67..8f6401a732 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronScheduler.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronScheduler.java @@ -4,19 +4,26 @@ import java.util.TimeZone; import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; import io.digdag.spi.ScheduleTime; -import io.digdag.spi.Scheduler; import it.sauronsoftware.cron4j.SchedulingPattern; import it.sauronsoftware.cron4j.Predictor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CronScheduler - implements Scheduler + extends BaseScheduler { + private static final Logger logger = LoggerFactory.getLogger(CronScheduler.class); + private final SchedulingPattern pattern; private final ZoneId timeZone; private final long delaySeconds; + protected final Optional start; + protected final Optional end; - CronScheduler(String cronPattern, ZoneId timeZone, long delaySeconds) + CronScheduler(String cronPattern, ZoneId timeZone, long delaySeconds, Optional start, Optional end) { this.pattern = new SchedulingPattern(cronPattern) { // workaround for a bug of cron4j: @@ -29,6 +36,8 @@ public boolean match(long millis) }; this.timeZone = timeZone; this.delaySeconds = delaySeconds; + this.start = start; + this.end = end; } @Override @@ -40,13 +49,11 @@ public ZoneId getTimeZone() @Override public ScheduleTime getFirstScheduleTime(Instant currentTime) { - Instant startTime = currentTime; // TODO make this from config - // truncate to seconds Instant truncated = Instant.ofEpochSecond(currentTime.getEpochSecond()); if (truncated.equals(currentTime)) { // in this particular case, minus 1 second to include this currentTime - // because Predictor doesn't include this time at "next"MatchingTime() method + // because Predictor doesn't include this time at nextMatchingTime() method truncated = truncated.minusSeconds(1); } Instant lastTime = truncated.minusSeconds(delaySeconds); @@ -57,8 +64,14 @@ public ScheduleTime getFirstScheduleTime(Instant currentTime) @Override public ScheduleTime nextScheduleTime(Instant lastScheduleTime) { - Instant next = next(lastScheduleTime); - return ScheduleTime.of(next, next.plusSeconds(delaySeconds)); + Instant next = nextWithStartEnd(lastScheduleTime); + + if (isScheduleFinished(next)) { + return ScheduleTime.of(next, next); + } + else { + return ScheduleTime.of(next, next.plusSeconds(delaySeconds)); + } } @Override @@ -92,4 +105,20 @@ private Instant next(Instant time) predictor.setTimeZone(TimeZone.getTimeZone(timeZone)); return Instant.ofEpochMilli(predictor.nextMatchingTime()); } + + private Instant nextWithStartEnd(Instant lastScheduleTime) + { + Instant next = next(lastScheduleTime); + Instant nextRun = next.plusSeconds(delaySeconds); + if (end.isPresent() && (end.get().equals(nextRun) || end.get().isBefore(nextRun))) { + logger.debug("next run time is after to end. next_run:{}, end:{}", nextRun, end.get()); + next = SCHEDULE_END; + } + else if (start.isPresent() && start.get().isAfter(nextRun)) { + logger.debug("next run time is before the start. next_run:{}, end:{}", nextRun, start.get()); + // next run is earlier than start. recalculate from start + next = next(start.get().minusSeconds(1)); // -1s is required because predictor doesn't include this time at nextMatchingTime() method + } + return next; + } } diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronSchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronSchedulerFactory.java index 6db3b98181..a0a3f711ef 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronSchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/CronSchedulerFactory.java @@ -1,6 +1,10 @@ package io.digdag.standards.scheduler; +import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.spi.Scheduler; import io.digdag.spi.SchedulerFactory; @@ -8,6 +12,14 @@ public class CronSchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public CronSchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -17,9 +29,16 @@ public String getType() @Override public Scheduler newScheduler(Config config, ZoneId timeZone) { + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + return new CronScheduler( config.get("_command", String.class), timeZone, - config.get("delay", long.class, 0L)); + config.get("delay", long.class, 0L), + start, + end + ); } } diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/DailySchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/DailySchedulerFactory.java index 37730f8609..d5c10f84ad 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/DailySchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/DailySchedulerFactory.java @@ -1,6 +1,10 @@ package io.digdag.standards.scheduler; +import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.client.config.ConfigException; import io.digdag.spi.Scheduler; @@ -9,6 +13,14 @@ public class DailySchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public DailySchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -19,7 +31,17 @@ public String getType() public Scheduler newScheduler(Config config, ZoneId timeZone) { String at = config.getOptional("_command", String.class).or(() -> config.get("at", String.class)); - return new CronScheduler("0 0 * * *", timeZone, parseAt("daily>", at)); + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + + return new CronScheduler( + "0 0 * * *", + timeZone, + parseAt("daily>", at), + start, + end + ); } static long parseAt(String kind, String at) diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/HourlySchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/HourlySchedulerFactory.java index ff68752b7d..834987e89b 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/HourlySchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/HourlySchedulerFactory.java @@ -1,6 +1,10 @@ package io.digdag.standards.scheduler; +import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.client.config.ConfigException; import io.digdag.spi.Scheduler; @@ -9,6 +13,14 @@ public class HourlySchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public HourlySchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -19,7 +31,17 @@ public String getType() public Scheduler newScheduler(Config config, ZoneId timeZone) { String at = config.getOptional("_command", String.class).or(() -> config.get("at", String.class)); - return new CronScheduler("0 * * * *", timeZone, parseAt(at)); + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + + return new CronScheduler( + "0 * * * *", + timeZone, + parseAt(at), + start, + end + ); } private long parseAt(String at) diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerFactory.java index 7cc1434954..870995248e 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerFactory.java @@ -1,6 +1,10 @@ package io.digdag.standards.scheduler; +import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.client.config.ConfigException; import io.digdag.spi.Scheduler; @@ -9,6 +13,14 @@ public class MinutesIntervalSchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public MinutesIntervalSchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -20,6 +32,16 @@ public Scheduler newScheduler(Config config, ZoneId timeZone) { int interval = config.get("_command", int.class); long delay = config.get("delay", long.class, 0L); - return new CronScheduler("*/" + interval + " * * * *", timeZone, delay); + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + + return new CronScheduler( + "*/" + interval + " * * * *", + timeZone, + delay, + start, + end + ); } } diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/MonthlySchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/MonthlySchedulerFactory.java index c58dde4b5d..f61a70ab8e 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/MonthlySchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/MonthlySchedulerFactory.java @@ -1,6 +1,10 @@ package io.digdag.standards.scheduler; +import java.time.Instant; import java.time.ZoneId; + +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.client.config.ConfigException; import io.digdag.spi.Scheduler; @@ -11,6 +15,14 @@ public class MonthlySchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public MonthlySchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -37,6 +49,16 @@ public Scheduler newScheduler(Config config, ZoneId timeZone) long dailyDelay = parseAt("monthly>", fragments[1]); - return new CronScheduler("0 0 " + day + " * *", timeZone, dailyDelay); + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + + return new CronScheduler( + "0 0 " + day + " * *", + timeZone, + dailyDelay, + start, + end + ); } } diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/ScheduleConfigHelper.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/ScheduleConfigHelper.java new file mode 100644 index 0000000000..00bfddce3a --- /dev/null +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/ScheduleConfigHelper.java @@ -0,0 +1,84 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.client.config.Config; +import io.digdag.client.config.ConfigException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.format.ResolverStyle; +import java.util.Locale; + + +public class ScheduleConfigHelper +{ + private static final Logger logger = LoggerFactory.getLogger(ScheduleConfigHelper.class); + + private DateTimeFormatter getFormatter() + { + return DateTimeFormatter + .ofPattern("uuuu-MM-dd", Locale.ENGLISH) //Not use 'yyyy'. strict mode requires 'uuuu' + .withResolverStyle(ResolverStyle.STRICT); //Check non existent day. + + } + + private LocalDate getLocalDate(String ymd) + { + return LocalDate.from(getFormatter().parse(ymd)); + } + + public Optional getDateTimeStart(Config config, String key, ZoneId zoneId) + throws ConfigException + { + Optional start = config.getOptional(key, String.class); + try { + Optional dt = start.transform(v -> { + LocalDateTime ldt = getLocalDate(v).atStartOfDay(); + ZonedDateTime zdt = ZonedDateTime.of(ldt, zoneId); + Instant it = Instant.ofEpochSecond(zdt.toEpochSecond()); + return it; + }); + return dt; + } + catch(DateTimeParseException dpe) { + throw new ConfigException(String.format("Invalid start: %s (%s)", start.or(""), dpe)); + } + } + + public Optional getDateTimeEnd(Config config, String key, ZoneId zoneId) + throws ConfigException + { + Optional end = config.getOptional(key, String.class); + try { + Optional dt = end.transform(v -> { + LocalDateTime ldt = getLocalDate(v).plusDays(1).atStartOfDay(); // add 1 day to include the end of the day + ZonedDateTime zdt = ZonedDateTime.of(ldt, zoneId); + Instant it = zdt.toInstant(); + return it; + }); + return dt; + } + catch(DateTimeParseException dpe) { + throw new ConfigException(String.format("Invalid end: %s (%s)", end.or(""), dpe)); + } + } + + public void validateStartEnd(Optional start, Optional end) + throws ConfigException + { + if (start.isPresent() && end.isPresent()) { + Instant s = start.get(); + Instant e = end.get(); + if (s.equals(e) || s.isAfter(e)) { + throw new ConfigException("The schedule of end is earlier than start"); + } + } + } +} diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/SchedulerModule.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/SchedulerModule.java index 3a957b9f71..f09ef57c30 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/SchedulerModule.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/SchedulerModule.java @@ -4,6 +4,7 @@ import com.google.inject.Module; import com.google.inject.Scopes; import com.google.inject.multibindings.Multibinder; +import io.digdag.core.schedule.SchedulerManager; import io.digdag.spi.SchedulerFactory; import io.digdag.standards.scheduler.CronSchedulerFactory; import io.digdag.standards.scheduler.MonthlySchedulerFactory; @@ -25,6 +26,7 @@ public void configure(Binder binder) addStandardSchedulerFactory(binder, HourlySchedulerFactory.class); addStandardSchedulerFactory(binder, MinutesIntervalSchedulerFactory.class); addStandardSchedulerFactory(binder, SecondsIntervalSchedulerFactory.class); + binder.bind(ScheduleConfigHelper.class).in(Scopes.SINGLETON); } protected void addStandardSchedulerFactory(Binder binder, Class factory) diff --git a/digdag-standards/src/main/java/io/digdag/standards/scheduler/WeeklySchedulerFactory.java b/digdag-standards/src/main/java/io/digdag/standards/scheduler/WeeklySchedulerFactory.java index 775113919c..28b08e9517 100644 --- a/digdag-standards/src/main/java/io/digdag/standards/scheduler/WeeklySchedulerFactory.java +++ b/digdag-standards/src/main/java/io/digdag/standards/scheduler/WeeklySchedulerFactory.java @@ -1,11 +1,14 @@ package io.digdag.standards.scheduler; +import com.google.common.base.Optional; +import com.google.inject.Inject; import io.digdag.client.config.Config; import io.digdag.client.config.ConfigException; import io.digdag.spi.Scheduler; import io.digdag.spi.SchedulerFactory; import it.sauronsoftware.cron4j.SchedulingPattern; +import java.time.Instant; import java.time.ZoneId; import static io.digdag.standards.scheduler.DailySchedulerFactory.parseAt; @@ -13,6 +16,14 @@ public class WeeklySchedulerFactory implements SchedulerFactory { + private final ScheduleConfigHelper configHelper; + + @Inject + public WeeklySchedulerFactory(ScheduleConfigHelper configHelper) + { + this.configHelper = configHelper; + } + @Override public String getType() { @@ -50,6 +61,16 @@ public Scheduler newScheduler(Config config, ZoneId timeZone) throw new ConfigException("weekly>: scheduler requires day,hh:mm:ss format: " + desc); } - return new CronScheduler(cronPattern, timeZone, dailyDelay); + Optional start = configHelper.getDateTimeStart(config, "start", timeZone); + Optional end = configHelper.getDateTimeEnd(config, "end", timeZone); + configHelper.validateStartEnd(start, end); + + return new CronScheduler( + cronPattern, + timeZone, + dailyDelay, + start, + end + ); } } diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/CronSchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/CronSchedulerTest.java new file mode 100644 index 0000000000..fb480ccb6b --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/CronSchedulerTest.java @@ -0,0 +1,403 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.spi.ScheduleTime; +import io.digdag.spi.Scheduler; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class CronSchedulerTest extends SchedulerTestHelper +{ + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) + { + return new CronSchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); + } + + @Test + public void firstScheduleTimeUtc() + { + // schedule is 10:00:00 every day + + // current time is 09:59:59 + { + Instant currentTime = instant("2016-02-03 09:59:59 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 10:00:00 +0000"), + instant("2016-02-03 10:00:00 +0000")))); + } + + // current time is 10:00:00 + { + Instant currentTime = instant("2016-02-03 10:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 10:00:00 +0000"), + instant("2016-02-03 10:00:00 +0000")))); + } + + // current time is 10:00:01 + { + Instant currentTime = instant("2016-02-03 10:00:01 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-04 10:00:00 +0000"), + instant("2016-02-04 10:00:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeTz() + { + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant currentTime = instant("2016-02-03 09:59:59 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 10:00:00 +0900"), + instant("2016-02-03 10:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 10:00:00 +0900"), + instant("2016-02-03 10:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:01 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-04 10:00:00 +0900"), + instant("2016-02-04 10:00:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-03-01 09:12:34 -0800"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 10:00:00 -0800"), + instant("2016-03-01 10:00:00 -0800")))); + } + // Current is at DST, first will be at DST + { + Instant currentTime = instant("2016-03-14 16:01:50 -0700"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-15 10:00:00 -0700"), + instant("2016-03-15 10:00:00 -0700")))); + } + + // Current is at before DST, first will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:59 -0800"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 10:00:00 -0700"), + instant("2016-03-13 10:00:00 -0700")))); + } + } + + @Test + public void firstScheduleTimeMisc() + { + //Test for the currentTime with boundary value 00:00:00 + { + Instant currentTime1 = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").getFirstScheduleTime(currentTime1), + is(ScheduleTime.of( + instant("2016-03-13 10:00:00 +0000"), + instant("2016-03-13 10:00:00 +0000")))); + } + //Test for the currentTime with boundary value 10:00:00 + { + Instant currentTime2 = instant("2016-03-13 10:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").getFirstScheduleTime(currentTime2), + is(ScheduleTime.of( + instant("2016-03-13 10:00:00 +0000"), + instant("2016-03-13 10:00:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeStartEnd() + { + // check start + { + Instant currentTime = instant("2016-02-03 09:59:59 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 10:00:00 +0000"), + instant("2016-03-01 10:00:00 +0000")))); + } + + // check end + { + Instant currentTime = instant("2016-03-31 10:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 10:00:00 +0000"), + instant("2016-03-31 10:00:00 +0000")))); + } + + // check end + { + Instant currentTime = instant("2016-03-31 10:00:01 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + + } + + @Test + public void nextScheduleTimeUtc() + { + // last schedule time is 00:00:00 + // schedule is 10:00:00 every day + { + Instant lastScheduleTime = instant("2016-02-03 10:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-04 10:00:00 +0000"), + instant("2016-02-04 10:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeTz() + { + // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant lastScheduleTime = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-04 10:00:00 +0900"), + instant("2016-02-04 10:00:00 +0900")))); + } + } + + @Test + public void nextScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + //last is before DST, next in before DST + { + Instant lastScheduleTime = instant("2016-03-01 10:00:00 -0800"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-02 10:00:00 -0800"), + instant("2016-03-02 10:00:00 -0800")))); + } + //last is after DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-14 10:00:00 -0700"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-15 10:00:00 -0700"), + instant("2016-03-15 10:00:00 -0700")))); + } + //last is before DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-12 10:00:00 -0800"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 10:00:00 -0700"), + instant("2016-03-13 10:00:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + // check start + { + Instant lastScheduleTime = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 10:00:00 +0900"), + instant("2016-03-01 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime = instant("2016-02-29 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 10:00:00 +0900"), + instant("2016-03-01 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime = instant("2016-03-01 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-02 10:00:00 +0900"), + instant("2016-03-02 10:00:00 +0900")))); + } + // check end (next will be 03-31. It is still within end) + { + Instant lastScheduleTime = instant("2016-03-30 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 10:00:00 +0900"), + instant("2016-03-31 10:00:00 +0900")))); + } + // check end (next will be 04-01. It is later than end) + { + Instant lastScheduleTime = instant("2016-03-31 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end (next will be 04-02. It is later than end) + { + Instant lastScheduleTime = instant("2016-04-01 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + + @Test + public void lastScheduleTimeUtc() + { + { + Instant currentScheduleTime = instant("2016-02-03 10:00:00 +0000"); + assertThat( + newScheduler("00 10 * * *", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 10:00:00 +0000"), + instant("2016-02-02 10:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeTz() + { + { + Instant currentScheduleTime = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 10:00:00 +0900"), + instant("2016-02-02 10:00:00 +0900")))); + } + } + + @Test + public void lastScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-12 10:00:00 -0800"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-11 10:00:00 -0800"), + instant("2016-03-11 10:00:00 -0800")))); + } + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime = instant("2016-03-14 10:00:00 -0700"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 10:00:00 -0700"), + instant("2016-03-13 10:00:00 -0700")))); + } + // current at DST(-0700), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-13 10:00:00 -0700"); + assertThat( + newScheduler("00 10 * * *", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 10:00:00 -0800"), + instant("2016-03-12 10:00:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + { + Instant currentScheduleTime = instant("2016-03-12 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-11 10:00:00 +0900"), + instant("2016-03-11 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-01 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-29 10:00:00 +0900"), + instant("2016-02-29 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-01 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 10:00:00 +0900"), + instant("2016-03-31 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-02 10:00:00 +0900"); + assertThat( + newScheduler("00 10 * * *", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 10:00:00 +0900"), + instant("2016-04-01 10:00:00 +0900")))); + } + } +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/DailySchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/DailySchedulerTest.java index ccb5921f7c..ff626ff713 100644 --- a/digdag-standards/src/test/java/io/digdag/standards/scheduler/DailySchedulerTest.java +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/DailySchedulerTest.java @@ -3,26 +3,20 @@ import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import io.digdag.client.config.Config; -import io.digdag.client.config.ConfigFactory; + +import com.google.common.base.Optional; import io.digdag.spi.Scheduler; import io.digdag.spi.ScheduleTime; import org.junit.Test; import static java.util.Locale.ENGLISH; -import static io.digdag.client.DigdagClient.objectMapper; import static org.hamcrest.Matchers.is; import static org.hamcrest.MatcherAssert.assertThat; -public class DailySchedulerTest +public class DailySchedulerTest extends SchedulerTestHelper { - static Config newConfig() + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) { - return new ConfigFactory(objectMapper()).create(); - } - - static Scheduler newScheduler(String pattern, String timeZone) - { - return new DailySchedulerFactory().newScheduler(newConfig().set("_command", pattern), ZoneId.of(timeZone)); + return new DailySchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); } private static DateTimeFormatter TIME_FORMAT = @@ -36,45 +30,60 @@ static Instant instant(String time) @Test public void firstScheduleTimeUtc() { - // current time is 09:00:00 - // schedule is 10:00:00 every day - // schedule at today 10:00:00 - Instant currentTime1 = instant("2016-02-03 09:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime1), - is(ScheduleTime.of( - instant("2016-02-03 00:00:00 +0000"), - instant("2016-02-03 10:00:00 +0000")))); - - // current time is 16:00:00 - // schedule is 10:00:00 every day - // schedule at tomorrow 10:00:00 - Instant currentTime2 = instant("2016-02-03 16:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime2), - is(ScheduleTime.of( - instant("2016-02-04 00:00:00 +0000"), - instant("2016-02-04 10:00:00 +0000")))); + { + Instant currentTime = instant("2016-02-03 09:34:12 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 10:00:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 10:00:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:01 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-04 00:00:00 +0000"), + instant("2016-02-04 10:00:00 +0000")))); + } } @Test public void firstScheduleTimeTz() { - // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo - - Instant currentTime1 = instant("2016-02-03 09:00:00 +0900"); - assertThat( - newScheduler("10:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime1), - is(ScheduleTime.of( - instant("2016-02-03 00:00:00 +0900"), - instant("2016-02-03 10:00:00 +0900")))); - - Instant currentTime2 = instant("2016-02-03 16:00:00 +0900"); - assertThat( - newScheduler("10:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime2), - is(ScheduleTime.of( - instant("2016-02-04 00:00:00 +0900"), - instant("2016-02-04 10:00:00 +0900")))); + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo (+0900) + { + Instant currentTime = instant("2016-02-03 09:34:12 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 10:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 10:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 10:00:01 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-04 00:00:00 +0900"), + instant("2016-02-04 10:00:00 +0900")))); + } } @Test @@ -82,137 +91,446 @@ public void firstScheduleTimeDst() { // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 // (== 2016-03-13 02:00:00 -0800) + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-03-11 12:34:56 -0800"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 10:00:00 -0800")))); + } + // Current is at DST, next first be at DST + { + Instant currentTime = instant("2016-03-13 16:31:03 -0700"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-14 00:00:00 -0700"), + instant("2016-03-14 10:00:00 -0700")))); + } - // This is an exceptional case with DST... + // Current is at DST, first session time will be at before DST, run time will be at DST // "daily> 10:00:00" means 10 hour later than 00:00:00. // 00:00:00 -08:00 plus 10 hours is 11:00:00 -07:00. - Instant currentTime1 = instant("2016-03-13 09:00:00 -0700"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime1), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 -0800"), - instant("2016-03-13 11:00:00 -0700")))); // schedule runs at 10:00:00 although definition is "daily> 10:00:00" + { + Instant currentTime = instant("2016-03-13 09:00:00 -0700"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 11:00:00 -0700")))); + } - Instant currentTime2 = instant("2016-03-13 16:00:00 -0700"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime2), - is(ScheduleTime.of( - instant("2016-03-14 00:00:00 -0700"), - instant("2016-03-14 10:00:00 -0700")))); + // Current is at before DST, first session time will be at before DST, run time will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:31 -0800"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 11:00:00 -0700")))); + } } @Test - public void firstScheduleTimeExact1() + public void firstScheduleTimeMisc() { - Instant currentTime1 = instant("2016-03-13 00:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime1), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 +0000"), - instant("2016-03-13 10:00:00 +0000")))); - - Instant currentTime2 = instant("2016-03-13 10:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime2), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 +0000"), - instant("2016-03-13 10:00:00 +0000")))); - - Instant currentTime3 = instant("2016-03-13 00:00:00 +0000"); - assertThat( - newScheduler("00:00:00", "UTC").getFirstScheduleTime(currentTime3), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 +0000"), - instant("2016-03-13 00:00:00 +0000")))); + // boundary test: current time is just 00:00:00 + { + Instant currentTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 +0000"), + instant("2016-03-13 10:00:00 +0000")))); + } + // boundary test: current time is same with "dail>: 10:00:00" + { + Instant currentTime = instant("2016-03-13 10:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 +0000"), + instant("2016-03-13 10:00:00 +0000")))); + } + // boundary test: schedule is set to 00:00:00 + { + Instant currentTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("00:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 +0000"), + instant("2016-03-13 00:00:00 +0000")))); + } } @Test - public void nextScheduleTimeUtc() - { + public void firstScheduleTimeStartEnd() { + // check start + { + Instant currentTime = instant("2016-02-03 09:59:59 +0000"); + assertThat( + newScheduler("10:00:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0000"), + instant("2016-03-01 10:00:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-02-03 09:59:59 +0000"); + assertThat( + newScheduler("23:59:59", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0000"), + instant("2016-03-01 23:59:59 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 10:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 +0000"), + instant("2016-03-31 10:00:00 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 10:00:01 +0000"); + assertThat( + newScheduler("10:00:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeUtc() { // last schedule time is 00:00:00 // schedule is 10:00:00 every day // next schedule time is at tomorrow 00:00:00 - Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").nextScheduleTime(lastScheduleTime1), - is(ScheduleTime.of( - instant("2016-02-04 00:00:00 +0000"), - instant("2016-02-04 10:00:00 +0000")))); + { + Instant lastScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-04 00:00:00 +0000"), + instant("2016-02-04 10:00:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2016-01-31 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0000"), + instant("2016-02-01 10:00:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2015-12-31 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0000"), + instant("2016-01-01 10:00:00 +0000")))); + } } @Test public void nextScheduleTimeTz() { // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo - - Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); - assertThat( - newScheduler("10:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), - is(ScheduleTime.of( - instant("2016-02-04 00:00:00 +0900"), - instant("2016-02-04 10:00:00 +0900")))); + { + Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-04 00:00:00 +0900"), + instant("2016-02-04 10:00:00 +0900")))); + } + { + Instant lastScheduleTime = instant("2016-01-31 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 10:00:00 +0900")))); + } + { + Instant lastScheduleTime = instant("2015-12-31 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0900"), + instant("2016-01-01 10:00:00 +0900")))); + } } @Test public void nextScheduleTimeDst() { - Instant lastScheduleTime1 = instant("2016-03-12 00:00:00 -0800"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime1), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 -0800"), - instant("2016-03-13 10:00:00 -0800")))); + { + Instant lastScheduleTime1 = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 10:00:00 -0800")))); + } + { + Instant lastScheduleTime2 = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime2), + is(ScheduleTime.of( + instant("2016-03-14 00:00:00 -0700"), + instant("2016-03-14 10:00:00 -0700")))); + } + } - Instant lastScheduleTime2 = instant("2016-03-13 00:00:00 -0800"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime2), - is(ScheduleTime.of( - instant("2016-03-14 00:00:00 -0700"), - instant("2016-03-14 10:00:00 -0700")))); + @Test + public void nextScheduleTimeMisc() { + //last schedule does not comply with the rule "YYYY-MM-DD 00:00:00" + { + Instant lastScheduleTime = instant("2016-03-02 12:34:56 -0800"); + assertThat( + newScheduler("10:11:23", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-03 00:00:00 -0800"), + instant("2016-03-03 10:11:23 -0800")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + // check start + { + Instant lastScheduleTime1 = instant("2016-02-03 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-02-29 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-03-01 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0900"), + instant("2016-03-02 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-03-30 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 +0900"), + instant("2016-03-31 10:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-03-31 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-04-01 10:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } } @Test public void lastScheduleTimeUtc() { - // last schedule time is 00:00:00 - // schedule is 10:00:00 every day - // next schedule time is at tomorrow 00:00:00 - Instant currentScheduleTime1 = instant("2016-02-03 00:00:00 +0000"); - assertThat( - newScheduler("10:00:00", "UTC").lastScheduleTime(currentScheduleTime1), - is(ScheduleTime.of( - instant("2016-02-02 00:00:00 +0000"), - instant("2016-02-02 10:00:00 +0000")))); + { + Instant currentScheduleTime = instant("2016-02-02 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0000"), + instant("2016-02-01 10:00:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-02-01 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-31 00:00:00 +0000"), + instant("2016-01-31 10:00:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-01-01 00:00:00 +0000"); + assertThat( + newScheduler("10:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2015-12-31 00:00:00 +0000"), + instant("2015-12-31 10:00:00 +0000")))); + } } @Test public void lastScheduleTimeTz() { // same with lastScheduleTimeUtc but with TZ=Asia/Tokyo - - Instant currentScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); - assertThat( - newScheduler("10:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime1), - is(ScheduleTime.of( - instant("2016-02-02 00:00:00 +0900"), - instant("2016-02-02 10:00:00 +0900")))); + { + Instant currentScheduleTime = instant("2016-02-02 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-02-01 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-31 00:00:00 +0900"), + instant("2016-01-31 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-01-01 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2015-12-31 00:00:00 +0900"), + instant("2015-12-31 10:00:00 +0900")))); + } } @Test public void lastScheduleTimeDst() { - Instant currentScheduleTime1 = instant("2016-03-13 00:00:00 -0800"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime1), - is(ScheduleTime.of( - instant("2016-03-12 00:00:00 -0800"), - instant("2016-03-12 10:00:00 -0800")))); - - Instant currentScheduleTime2 = instant("2016-03-14 00:00:00 -0700"); - assertThat( - newScheduler("10:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime2), - is(ScheduleTime.of( - instant("2016-03-13 00:00:00 -0800"), - instant("2016-03-13 10:00:00 -0800")))); + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 10:00:00 -0800")))); + } + + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime = instant("2016-03-15 00:00:00 -0700"); + assertThat( + newScheduler("01:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-14 00:00:00 -0700"), + instant("2016-03-14 01:00:00 -0700")))); + } + + // current at DST(-0700), last will be at before DST(-0800) + { + Instant currentScheduleTime = instant("2016-03-14 00:00:00 -0700"); + assertThat( + newScheduler("01:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 01:00:00 -0800")))); + } + + // current at DST(-0700), last session time will be at before DST(-0800), run time will be at DST(-0700) + { + Instant currentScheduleTime = instant("2016-03-14 00:00:00 -0700"); + assertThat( + newScheduler("05:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 06:00:00 -0700")))); + } + } + + @Test + public void lastScheduleTimeMisc() + { + // current schedule time does not comply with Monthly>'s one = 'YYYY-MM-DD 00:00:00' + { + Instant currentScheduleTime = instant("2016-09-13 12:34:56 -0700"); + assertThat( + newScheduler("10:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-09-13 00:00:00 -0700"), + instant("2016-09-13 10:00:00 -0700")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + + { + Instant currentScheduleTime = instant("2016-02-29 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-28 00:00:00 +0900"), + instant("2016-02-28 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-29 00:00:00 +0900"), + instant("2016-02-29 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-02 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-31 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-30 00:00:00 +0900"), + instant("2016-03-30 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-01 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 +0900"), + instant("2016-03-31 10:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-02 00:00:00 +0900"); + assertThat( + newScheduler("10:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 +0900"), + instant("2016-04-01 10:00:00 +0900")))); + } } } diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/HourlySchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/HourlySchedulerTest.java new file mode 100644 index 0000000000..c892bfc7b2 --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/HourlySchedulerTest.java @@ -0,0 +1,436 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.spi.ScheduleTime; +import io.digdag.spi.Scheduler; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class HourlySchedulerTest extends SchedulerTestHelper +{ + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) + { + return new HourlySchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); + } + + @Test + public void firstScheduleTimeUtc() + { + { + Instant currentTime = instant("2016-02-03 17:14:59 +0000"); + assertThat( + newScheduler("15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:00 +0000"); + assertThat( + newScheduler("15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:01 +0000"); + assertThat( + newScheduler("15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 18:00:00 +0000"), + instant("2016-02-03 18:15:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeTz() + { + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant currentTime = instant("2016-02-03 17:14:59 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:01 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 18:00:00 +0900"), + instant("2016-02-03 18:15:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeDst() + { + // America/Los_Angeles(-0800) begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 00:15:00 -0800")))); + } + // Current is at DST, next first be at DST + { + Instant currentTime = instant("2016-03-13 16:00:00 -0700"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 16:00:00 -0700"), + instant("2016-03-13 16:15:00 -0700")))); + } + // Current is at before DST, first will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:00 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 03:00:00 -0700"), + instant("2016-03-13 03:15:00 -0700")))); + } + } + + @Test + public void firstScheduleTimeMisc() + { + //Test for the currentTime with boundary value 00:00:00 + { + Instant currentTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 +0000"), + instant("2016-03-13 00:15:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeStartEnd() + { + // check start + { + Instant currentTime = instant("2016-02-03 17:14:59 +0000"); + assertThat( + newScheduler("15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0000"), + instant("2016-03-01 00:15:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-03-01 00:15:01 +0000"); + assertThat( + newScheduler("15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 01:00:00 +0000"), + instant("2016-03-01 01:15:00 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 23:15:00 +0000"); + assertThat( + newScheduler("15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 23:00:00 +0000"), + instant("2016-03-31 23:15:00 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 23:15:01 +0000"); + assertThat( + newScheduler("15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeUtc() + { + // last schedule time is 00:00:00 + // schedule is 10:00:00 every day + { + Instant lastScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("15:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 01:00:00 +0000"), + instant("2016-02-03 01:15:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeTz() + { + // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-03 01:00:00 +0900"), + instant("2016-02-03 01:15:00 +0900")))); + } + } + + @Test + public void nextScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + //last is before DST, next in before DST + { + Instant lastScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 01:00:00 -0800"), + instant("2016-03-13 01:15:00 -0800")))); + } + //last is after DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-13 03:00:00 -0700"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 04:00:00 -0700"), + instant("2016-03-13 04:15:00 -0700")))); + } + //last is before DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-13 01:00:00 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 03:00:00 -0700"), + instant("2016-03-13 03:15:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeMisc() { + //last schedule does not comply with the rule of hourly> as 'hh:00:00' + { + Instant lastScheduleTime = instant("2016-03-13 00:12:34 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 01:00:00 -0800"), + instant("2016-03-13 01:15:00 -0800")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + //check start + { + Instant lastScheduleTime1 = instant("2016-02-29 05:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 00:15:00 +0900")))); + } + //check start + { + Instant lastScheduleTime1 = instant("2016-02-29 23:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 00:15:00 +0900")))); + } + //check start + { + Instant lastScheduleTime1 = instant("2016-03-01 00:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 01:00:00 +0900"), + instant("2016-03-01 01:15:00 +0900")))); + } + //check end + { + Instant lastScheduleTime1 = instant("2016-03-31 22:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-31 23:00:00 +0900"), + instant("2016-03-31 23:15:00 +0900")))); + } + //check end + { + Instant lastScheduleTime1 = instant("2016-03-31 23:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + //check end + { + Instant lastScheduleTime1 = instant("2016-04-01 00:15:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeUtc() + { + { + Instant currentScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("15:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 23:00:00 +0000"), + instant("2016-02-02 23:15:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeTz() + { + { + Instant currentScheduleTime = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 23:00:00 +0900"), + instant("2016-02-02 23:15:00 +0900")))); + } + } + + @Test + public void lastScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 23:00:00 -0800"), + instant("2016-03-12 23:15:00 -0800")))); + } + + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime2 = instant("2016-03-14 00:00:00 -0700"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime2), + is(ScheduleTime.of( + instant("2016-03-13 23:00:00 -0700"), + instant("2016-03-13 23:15:00 -0700")))); + } + + // current at DST(-0700), last will be at before DST + { + Instant currentScheduleTime3 = instant("2016-03-13 05:00:00 -0700"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime3), + is(ScheduleTime.of( + instant("2016-03-13 04:00:00 -0700"), + instant("2016-03-13 04:15:00 -0700")))); + } + } + + @Test + public void lastScheduleTimeMisc() + { + // current schedule time does not comply with hourly>'s one = 'YYYY-MM-DD hh:00:00' + { + Instant currentScheduleTime = instant("2016-03-13 00:00:45 -0800"); + assertThat( + newScheduler("15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 00:15:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + { + Instant currentScheduleTime = instant("2016-02-29 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-28 23:00:00 +0900"), + instant("2016-02-28 23:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-29 23:00:00 +0900"), + instant("2016-02-29 23:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-02 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 23:00:00 +0900"), + instant("2016-03-01 23:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-31 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-30 23:00:00 +0900"), + instant("2016-03-30 23:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-01 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 23:00:00 +0900"), + instant("2016-03-31 23:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-02 00:00:00 +0900"); + assertThat( + newScheduler("15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 23:00:00 +0900"), + instant("2016-04-01 23:15:00 +0900")))); + } + } +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerTest.java new file mode 100644 index 0000000000..5ee764d3e2 --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/MinutesIntervalSchedulerTest.java @@ -0,0 +1,489 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.spi.ScheduleTime; +import io.digdag.spi.Scheduler; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class MinutesIntervalSchedulerTest extends SchedulerTestHelper +{ + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) + { + return new MinutesIntervalSchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); + } + + @Test + public void firstScheduleTimeUtc() + { + { + Instant currentTime = instant("2016-02-03 17:19:59 +0000"); + assertThat( + newScheduler("10", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:20:00 +0000"), + instant("2016-02-03 17:20:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:20:00 +0000"); + assertThat( + newScheduler("10", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:20:00 +0000"), + instant("2016-02-03 17:20:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:20:01 +0000"); + assertThat( + newScheduler("10", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:30:00 +0000"), + instant("2016-02-03 17:30:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeTz() + { + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant currentTime = instant("2016-02-03 17:19:59 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:20:00 +0900"), + instant("2016-02-03 17:20:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:20:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:20:00 +0900"), + instant("2016-02-03 17:20:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:20:01 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 17:30:00 +0900"), + instant("2016-02-03 17:30:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeDst() + { + // America/Los_Angeles(-0800) begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 00:00:00 -0800")))); + } + // Current is at DST, next first be at DST + { + Instant currentTime = instant("2016-03-13 16:00:00 -0700"); + assertThat( + newScheduler("10", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 16:00:00 -0700"), + instant("2016-03-13 16:00:00 -0700")))); + } + // Current is at before DST, first will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:00 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 03:00:00 -0700"), + instant("2016-03-13 03:00:00 -0700")))); + } + } + + @Test + public void firstScheduleTimeStartEnd() + { + // check start + { + Instant currentTime = instant("2016-03-03 17:19:59 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-03 17:20:00 +0900"), + instant("2016-03-03 17:20:00 +0900")))); + } + // check start + { + Instant currentTime = instant("2016-02-03 17:09:59 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 00:00:00 +0900")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 23:59:59 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-03-31 23:49:59 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 23:50:00 +0900"), + instant("2016-03-31 23:50:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeMisc() + { + //Test for indivisibility value "7" + + { + Instant currentTime = instant("2016-03-13 00:04:12 +0000"); + assertThat( + newScheduler("7", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:07:00 +0000"), + instant("2016-03-13 00:07:00 +0000")))); + } + { + Instant currentTime = instant("2016-03-13 00:55:12 +0000"); + assertThat( + newScheduler("7", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 00:56:00 +0000"), + instant("2016-03-13 00:56:00 +0000")))); + } + { + Instant currentTime = instant("2016-03-13 00:57:12 +0000"); + assertThat( + newScheduler("7", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 01:00:00 +0000"), + instant("2016-03-13 01:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeUtc() + { + { + Instant lastScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("10", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:10:00 +0000"), + instant("2016-02-03 00:10:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeTz() + { + // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-03 00:10:00 +0900"), + instant("2016-02-03 00:10:00 +0900")))); + } + } + + @Test + public void nextScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + //last is before DST, next in before DST + { + Instant lastScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:10:00 -0800"), + instant("2016-03-13 00:10:00 -0800")))); + } + //last is after DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-13 03:00:00 -0700"); + assertThat( + newScheduler("10", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 03:10:00 -0700"), + instant("2016-03-13 03:10:00 -0700")))); + } + //last is before DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-13 01:50:00 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 03:00:00 -0700"), + instant("2016-03-13 03:00:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeMisc() { + //last schedule does not comply with the rule of minuts_interval>' + { + Instant lastScheduleTime = instant("2016-03-13 00:12:34 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:20:00 -0800"), + instant("2016-03-13 00:20:00 -0800")))); + } + + //Test for indivisibility value "7" + { + Instant lastScheduleTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("7", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:07:00 +0000"), + instant("2016-03-13 00:07:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2016-03-13 00:56:00 +0000"); + assertThat( + newScheduler("7", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 01:00:00 +0000"), + instant("2016-03-13 01:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + // check start + { + Instant lastScheduleTime1 = instant("2016-02-03 00:40:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 00:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-02-29 23:50:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 00:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:10:00 +0900"), + instant("2016-03-01 00:10:00 +0900")))); + } + // check end + { + Instant lastScheduleTime1 = instant("2016-03-31 23:40:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-31 23:50:00 +0900"), + instant("2016-03-31 23:50:00 +0900")))); + } + // check end + { + Instant lastScheduleTime1 = instant("2016-03-31 23:50:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end + { + Instant lastScheduleTime1 = instant("2016-04-01 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeUtc() + { + { + Instant currentScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("10", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 23:50:00 +0000"), + instant("2016-02-02 23:50:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeTz() + { + { + Instant currentScheduleTime = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-02 23:50:00 +0900"), + instant("2016-02-02 23:50:00 +0900")))); + } + } + + @Test + public void lastScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 23:50:00 -0800"), + instant("2016-03-12 23:50:00 -0800")))); + } + + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime2 = instant("2016-03-14 00:00:00 -0700"); + assertThat( + newScheduler("10", "America/Los_Angeles").lastScheduleTime(currentScheduleTime2), + is(ScheduleTime.of( + instant("2016-03-13 23:50:00 -0700"), + instant("2016-03-13 23:50:00 -0700")))); + } + + // current at DST(-0700), last will be at before DST + { + Instant currentScheduleTime3 = instant("2016-03-13 03:00:00 -0700"); + assertThat( + newScheduler("10", "America/Los_Angeles").lastScheduleTime(currentScheduleTime3), + is(ScheduleTime.of( + instant("2016-03-13 01:50:00 -0800"), + instant("2016-03-13 01:50:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeMisc() + { + // current schedule time does not comply with hourly>'s one = 'YYYY-MM-DD hh:00:00' + { + Instant currentScheduleTime = instant("2016-03-13 00:00:45 -0800"); + assertThat( + newScheduler("10", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:00:00 -0800"), + instant("2016-03-13 00:00:00 -0800")))); + } + + //Test for indivisibility value "7" + { + Instant currentScheduleTime = instant("2016-03-13 00:00:00 -0800"); + assertThat( + newScheduler("7", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 23:56:00 -0800"), + instant("2016-03-12 23:56:00 -0800")))); + } + { + Instant currentScheduleTime = instant("2016-03-13 00:56:00 -0800"); + assertThat( + newScheduler("7", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-13 00:49:00 -0800"), + instant("2016-03-13 00:49:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + { + Instant currentScheduleTime = instant("2016-02-29 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-28 23:50:00 +0900"), + instant("2016-02-28 23:50:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-29 23:50:00 +0900"), + instant("2016-02-29 23:50:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-02 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 23:50:00 +0900"), + instant("2016-03-01 23:50:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-31 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-30 23:50:00 +0900"), + instant("2016-03-30 23:50:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-01 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 23:50:00 +0900"), + instant("2016-03-31 23:50:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-02 00:00:00 +0900"); + assertThat( + newScheduler("10", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-03-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 23:50:00 +0900"), + instant("2016-04-01 23:50:00 +0900")))); + } + } + + +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/MonthlySchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/MonthlySchedulerTest.java new file mode 100644 index 0000000000..a923c15906 --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/MonthlySchedulerTest.java @@ -0,0 +1,520 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.spi.ScheduleTime; +import io.digdag.spi.Scheduler; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class MonthlySchedulerTest extends SchedulerTestHelper +{ + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) + { + return new MonthlySchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); + } + + @Test + public void firstScheduleTimeUtc() + { + { + Instant currentTime = instant("2016-02-01 11:59:59 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0000"), + instant("2016-02-01 12:00:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-01 12:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0000"), + instant("2016-02-01 12:00:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-01 12:00:01 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0000"), + instant("2016-03-01 12:00:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeTz() + { + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant currentTime = instant("2016-02-01 11:59:59 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 12:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-01 12:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 12:00:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-01 12:00:01 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeDst() + { + // America/Los_Angeles(-0800) begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-02-12 06:12:34 -0800"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 -0800"), + instant("2016-03-01 12:00:00 -0800")))); + } + // Current is at DST, next first be at DST + { + Instant currentTime = instant("2016-03-13 16:00:00 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 -0700"), + instant("2016-04-01 12:00:00 -0700")))); + } + // Current is at before DST, first will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:00 -0800"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 -0700"), + instant("2016-04-01 12:00:00 -0700")))); + } + } + + @Test + public void firstScheduleTimeMisc() + { + //CurrentTime with boundary value 00:00:00 + { + Instant currentTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 +0000"), + instant("2016-04-01 12:00:00 +0000")))); + } + //Next year + { + Instant currentTime = instant("2016-12-03 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2017-01-01 00:00:00 +0000"), + instant("2017-01-01 12:00:00 +0000")))); + } + //Non existent day 02-31 + { + Instant currentTime = instant("2016-01-31 19:12:34 +0000"); + // 02-31 does not exist. So skip to 03-31. Strange. + assertThat( + newScheduler("31,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 +0000"), + instant("2016-03-31 12:00:00 +0000")))); + } + //Non existent day 06-31 + { + Instant currentTime = instant("2016-05-31 19:12:34 +0000"); + // 06-31 does not exist. So skip to 07-31. + assertThat( + newScheduler("31,12:00:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-07-31 00:00:00 +0000"), + instant("2016-07-31 12:00:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeStartEnd() + { + // check start + { + Instant currentTime = instant("2016-02-29 23:59:59 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + // check start + { + Instant currentTime = instant("2016-03-01 12:00:01 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 +0900"), + instant("2016-04-01 12:00:00 +0900")))); + } + // check start + { + Instant currentTime = instant("2016-02-29 23:59:59 +0900"); + assertThat( + newScheduler("31,23:59:59", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 +0900"), + instant("2016-03-31 23:59:59 +0900")))); + } + // check end + { + Instant currentTime = instant("2016-05-01 12:00:01 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end + { + Instant currentTime = instant("2016-06-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeUtc() + { + { + Instant lastScheduleTime = instant("2016-02-01 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0000"), + instant("2016-03-01 12:00:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2015-12-01 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0000"), + instant("2016-01-01 12:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeTz() + { + // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant lastScheduleTime1 = instant("2016-02-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + { + Instant lastScheduleTime1 = instant("2015-12-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0900"), + instant("2016-01-01 12:00:00 +0900")))); + } + } + + @Test + public void nextScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + //last is before DST, next in before DST + { + Instant lastScheduleTime = instant("2016-01-01 00:00:00 -0800"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 -0800"), + instant("2016-02-01 12:00:00 -0800")))); + } + //last is after DST, next in DST + { + Instant lastScheduleTime = instant("2016-04-01 00:00:00 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-05-01 00:00:00 -0700"), + instant("2016-05-01 12:00:00 -0700")))); + } + //last is before DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-01 00:00:00 -0800"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 -0700"), + instant("2016-04-01 12:00:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeMisc() { + //last schedule does not comply with the rule "YYYY-MM-DD 00:00:00" + { + Instant lastScheduleTime = instant("2016-03-13 12:34:56 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 -0700"), + instant("2016-04-01 12:00:00 -0700")))); + } + //Non existent day 02-31 + { + Instant lastScheduleTime = instant("2016-01-31 00:00:00 -0800"); + assertThat( + newScheduler("31,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-31 00:00:00 -0700"), + instant("2016-03-31 12:00:00 -0700")))); + } + //Non existent day 06-31 + { + Instant lastScheduleTime = instant("2016-05-31 00:00:00 -0800"); + assertThat( + newScheduler("31,12:00:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-07-31 00:00:00 -0700"), + instant("2016-07-31 12:00:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + // check start + { + Instant lastScheduleTime1 = instant("2016-01-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-02-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + // check start + { + Instant lastScheduleTime1 = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 +0900"), + instant("2016-04-01 12:00:00 +0900")))); + } + // check end + { + Instant lastScheduleTime1 = instant("2016-05-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end + { + Instant lastScheduleTime1 = instant("2016-06-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeUtc() + { + { + Instant currentScheduleTime = instant("2016-02-01 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0000"), + instant("2016-01-01 12:00:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-01-31 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0000"), + instant("2016-01-01 12:00:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-02-02 00:00:00 +0000"); + assertThat( + newScheduler("1,12:00:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0000"), + instant("2016-02-01 12:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeTz() + { + //2016-02-09:Tue 02-10:Wed 02-11:Thu + { + Instant currentScheduleTime = instant("2016-02-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0900"), + instant("2016-01-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-01-31 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0900"), + instant("2016-01-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-02-02 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 12:00:00 +0900")))); + } + } + + @Test + public void lastScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + // 2016-03-12:Sat + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-01 00:00:00 -0800"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 -0800"), + instant("2016-02-01 12:00:00 -0800")))); + } + + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime2 = instant("2016-05-01 00:00:00 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime2), + is(ScheduleTime.of( + instant("2016-04-01 00:00:00 -0700"), + instant("2016-04-01 12:00:00 -0700")))); + } + + // current at DST(-0700), last will be at before DST(-0800) + { + Instant currentScheduleTime3 = instant("2016-04-01 00:00:00 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime3), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 -0800"), + instant("2016-03-01 12:00:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeMisc() + { + // current schedule time does not comply with Monthly>'s one = 'YYYY-MM-DD 00:00:00' + { + Instant currentScheduleTime = instant("2016-09-13 12:34:56 -0700"); + assertThat( + newScheduler("1,12:00:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-09-01 00:00:00 -0700"), + instant("2016-09-01 12:00:00 -0700")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + { + Instant currentScheduleTime = instant("2016-02-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-01-01 00:00:00 +0900"), + instant("2016-01-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-01 00:00:00 +0900"), + instant("2016-02-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-04-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-01 00:00:00 +0900"), + instant("2016-03-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-06-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-05-01 00:00:00 +0900"), + instant("2016-05-01 12:00:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-07-01 00:00:00 +0900"); + assertThat( + newScheduler("1,12:00:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-06-01 00:00:00 +0900"), + instant("2016-06-01 12:00:00 +0900")))); + } + } +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/ScheduleConfigHelperTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/ScheduleConfigHelperTest.java new file mode 100644 index 0000000000..121790a19a --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/ScheduleConfigHelperTest.java @@ -0,0 +1,87 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.client.config.Config; +import io.digdag.client.config.ConfigException; +import io.digdag.client.config.ConfigFactory; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static io.digdag.client.DigdagClient.objectMapper; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ScheduleConfigHelperTest { + static Config newConfig() { + return new ConfigFactory(objectMapper()).create(); + } + + private ScheduleConfigHelper helper = new ScheduleConfigHelper(); + + @Test + public void testStart() + { + Config config = newConfig() + .set("start", "2022-03-15") + .set("end", "2022-04-30"); + // Expected "2022-03-15T00:00:00+0900 (1647270000)" + assertThat(helper.getDateTimeStart(config, "start", ZoneId.of("Asia/Tokyo")), is(Optional.of(Instant.ofEpochSecond(1647270000L)))); + // Expected "2022-03-15T00:00:00+0000 (1647302400)" + assertThat(helper.getDateTimeStart(config, "start", ZoneId.of("UTC")), is(Optional.of(Instant.ofEpochSecond(1647302400L)))); + } + + @Test + public void testEnd() + { + Config config = newConfig() + .set("start", "2022-03-15") + .set("end", "2022-04-30"); + // Expected "2022-05-01T00:00:00+0900 (1651330800)" + assertThat(helper.getDateTimeEnd(config, "end", ZoneId.of("Asia/Tokyo")), is(Optional.of(Instant.ofEpochSecond(1651330800L)))); + // Expected "2022-05-01T00:00:00+0000 (1651363200)" + assertThat(helper.getDateTimeEnd(config, "end", ZoneId.of("UTC")), is(Optional.of(Instant.ofEpochSecond(1651363200L)))); + } + + @Test(expected = ConfigException.class) + public void testNonExistentDate() + { + // Non existent date + Config config = newConfig() + .set("start", "2022-04-31"); + System.out.println(helper.getDateTimeStart(config, "start", ZoneId.of("Asia/Tokyo"))); + } + + @Test(expected = ConfigException.class) + public void testInvalidFormat() + { + // Non existent date + Config config = newConfig() + .set("start", "2022-04-ii"); + System.out.println(helper.getDateTimeStart(config, "start", ZoneId.of("Asia/Tokyo"))); + } + + @Test + public void testValidateStartEndSuccess() + { + helper.validateStartEnd(Optional.of(Instant.ofEpochSecond(1651330801L)), Optional.of(Instant.ofEpochSecond(1651330802L))); + } + + @Test(expected = ConfigException.class) + public void testValidateStartEndFail1() + { + helper.validateStartEnd(Optional.of(Instant.ofEpochSecond(1651330801L)), Optional.of(Instant.ofEpochSecond(1651330800L))); + } + + @Test(expected = ConfigException.class) + public void testValidateStartEndFail2() + { + // Can't accept start == end because end date will be added 1day internally + // start: 2022-04-02 + // end: 2022-04-01 + // In above case, start will be parsed as "2022-04-02 00:00:00" and end will be parsed as "2022-04-02 00:00:00" (plus 1day) + helper.validateStartEnd(Optional.of(Instant.ofEpochSecond(1651330801L)), Optional.of(Instant.ofEpochSecond(1651330801L))); + } + +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/SchedulerTestHelper.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/SchedulerTestHelper.java new file mode 100644 index 0000000000..de1a4007f0 --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/SchedulerTestHelper.java @@ -0,0 +1,45 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.client.config.Config; +import io.digdag.client.config.ConfigFactory; +import io.digdag.spi.Scheduler; + +import java.time.Instant; +import java.time.format.DateTimeFormatter; + +import static io.digdag.client.DigdagClient.objectMapper; +import static java.util.Locale.ENGLISH; + +abstract class SchedulerTestHelper +{ + final ScheduleConfigHelper configHelper = new ScheduleConfigHelper(); + + private static DateTimeFormatter TIME_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z", ENGLISH); + + static Config newConfig() + { + return new ConfigFactory(objectMapper()).create(); + } + + static Config newConfig(String command, Optional start, Optional end) + { + Config config = new ConfigFactory(objectMapper()).create().set("_command", command); + config = start.isPresent() ? config.set("start", start.get()) : config; + config = end.isPresent() ? config.set("end", end.get()) : config; + return config; + } + + static Instant instant(String time) + { + return Instant.from(TIME_FORMAT.parse(time)); + } + + Scheduler newScheduler(String pattern, String timeZone) + { + return newScheduler(pattern, timeZone, Optional.absent(), Optional.absent()); + } + + abstract Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end); +} diff --git a/digdag-standards/src/test/java/io/digdag/standards/scheduler/WeeklySchedulerTest.java b/digdag-standards/src/test/java/io/digdag/standards/scheduler/WeeklySchedulerTest.java new file mode 100644 index 0000000000..7232b7b6e1 --- /dev/null +++ b/digdag-standards/src/test/java/io/digdag/standards/scheduler/WeeklySchedulerTest.java @@ -0,0 +1,528 @@ +package io.digdag.standards.scheduler; + +import com.google.common.base.Optional; +import io.digdag.spi.ScheduleTime; +import io.digdag.spi.Scheduler; +import org.junit.Test; + +import java.time.Instant; +import java.time.ZoneId; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class WeeklySchedulerTest extends SchedulerTestHelper +{ + Scheduler newScheduler(String pattern, String timeZone, Optional start, Optional end) + { + return new WeeklySchedulerFactory(configHelper).newScheduler(newConfig(pattern, start, end), ZoneId.of(timeZone)); + } + + @Test + public void firstScheduleTimeUtc() + { + // 2016-02-03 Wed. + { + Instant currentTime = instant("2016-02-03 17:14:59 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:01 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0000"), + instant("2016-02-10 17:15:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeTz() + { + // same with firstScheduleTimeUtc but with TZ=Asia/Tokyo + // 2016-02-03 Wed. + { + Instant currentTime = instant("2016-02-03 17:14:59 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentTime = instant("2016-02-03 17:15:01 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0900"), + instant("2016-02-10 17:15:00 +0900")))); + } + } + + @Test + public void firstScheduleTimeDst() + { + // America/Los_Angeles(-0800) begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + // 2016-03-13 Sun + // Current is at before DST, first will be at before DST + { + Instant currentTime = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("Sat,15:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 15:00:00 -0800")))); + } + // Current is at DST, next first be at DST + { + Instant currentTime = instant("2016-03-13 16:00:00 -0700"); + assertThat( + newScheduler("Sat,15:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-19 00:00:00 -0700"), + instant("2016-03-19 15:00:00 -0700")))); + } + // Current is at before DST, first will be at DST + { + Instant currentTime = instant("2016-03-13 01:59:00 -0800"); + assertThat( + newScheduler("Sun,15:00:00", "America/Los_Angeles").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-13 01:00:00 -0700"), + instant("2016-03-13 16:00:00 -0700")))); + } + } + + @Test + public void firstScheduleTimeMisc() + { + //Test for the currentTime with boundary value 00:00:00 + { + Instant currentTime = instant("2016-03-13 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-16 00:00:00 +0000"), + instant("2016-03-16 17:15:00 +0000")))); + } + } + + @Test + public void firstScheduleTimeStartEnd() + { + // 2016-02-03 Wed. 2016-03-01 Tue. + // check start + { + Instant currentTime = instant("2016-02-03 17:14:59 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-02-03 17:15:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-02-03 17:15:01 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-02-29 23:59:59 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant currentTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check end 2016-03-30 Wed. + { + Instant currentTime = instant("2016-03-30 17:15:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("2016-03-30 00:00:00 +0000"), + instant("2016-03-30 17:15:00 +0000")))); + } + // check end 2016-03-30 Wed. + { + Instant currentTime = instant("2016-03-30 17:15:01 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).getFirstScheduleTime(currentTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeUtc() + { + //2016-02-02:Tue 02-03:Wed 02-04:Thu. + { + Instant lastScheduleTime = instant("2016-02-02 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2016-02-03 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0000"), + instant("2016-02-10 17:15:00 +0000")))); + } + { + Instant lastScheduleTime = instant("2016-02-04 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0000"), + instant("2016-02-10 17:15:00 +0000")))); + } + } + + @Test + public void nextScheduleTimeTz() + { + // same with nextScheduleTimeUtc but with TZ=Asia/Tokyo + { + Instant lastScheduleTime1 = instant("2016-02-02 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant lastScheduleTime1 = instant("2016-02-03 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0900"), + instant("2016-02-10 17:15:00 +0900")))); + } + { + Instant lastScheduleTime1 = instant("2016-02-04 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").nextScheduleTime(lastScheduleTime1), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0900"), + instant("2016-02-10 17:15:00 +0900")))); + } + } + + @Test + public void nextScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + // 2016-03-12 Sat. + //last is before DST, next in before DST + { + Instant lastScheduleTime = instant("2016-03-05 00:00:00 -0800"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 17:15:00 -0800")))); + } + //last is after DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-19 00:00:00 -0700"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-26 00:00:00 -0700"), + instant("2016-03-26 17:15:00 -0700")))); + } + //last is before DST, next in DST + { + Instant lastScheduleTime = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-19 00:00:00 -0700"), + instant("2016-03-19 17:15:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeMisc() { + //last schedule does not comply with the rule "YYYY-MM-DD 00:00:00" + //2016-03-13:Sun + { + Instant lastScheduleTime = instant("2016-03-13 12:34:56 -0700"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-19 00:00:00 -0700"), + instant("2016-03-19 17:15:00 -0700")))); + } + } + + @Test + public void nextScheduleTimeStartEnd() + { + //2016-02-17:Wed 02-24:Wed + + // check start + { + Instant lastScheduleTime = instant("2016-02-17 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant lastScheduleTime = instant("2016-02-24 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0000"), + instant("2016-03-02 17:15:00 +0000")))); + } + // check start + { + Instant lastScheduleTime = instant("2016-03-02 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-09 00:00:00 +0000"), + instant("2016-03-09 17:15:00 +0000")))); + } + // check end + { + Instant lastScheduleTime = instant("2016-03-23 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("2016-03-30 00:00:00 +0000"), + instant("2016-03-30 17:15:00 +0000")))); + } + // check end + { + Instant lastScheduleTime = instant("2016-03-30 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + // check end + { + Instant lastScheduleTime = instant("2016-04-06 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC", Optional.of("2016-03-01"), Optional.of("2016-03-31")).nextScheduleTime(lastScheduleTime), + is(ScheduleTime.of( + instant("9999-01-01 00:00:00 +0000"), + instant("9999-01-01 00:00:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeUtc() + { + //2016-02-09:Tue 02-10:Wed 02-11:Thu + { + Instant currentScheduleTime = instant("2016-02-09 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-02-10 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0000"), + instant("2016-02-03 17:15:00 +0000")))); + } + { + Instant currentScheduleTime = instant("2016-02-11 00:00:00 +0000"); + assertThat( + newScheduler("Wed,17:15:00", "UTC").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0000"), + instant("2016-02-10 17:15:00 +0000")))); + } + } + + @Test + public void lastScheduleTimeTz() + { + //2016-02-09:Tue 02-10:Wed 02-11:Thu + { + Instant currentScheduleTime = instant("2016-02-09 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-02-10 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-02-11 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-10 00:00:00 +0900"), + instant("2016-02-10 17:15:00 +0900")))); + } + } + + @Test + public void lastScheduleTimeDst() + { + // America/Los_Angeles begins DST at 2016-03-13 03:00:00 -0700 + // (== 2016-03-13 02:00:00 -0800) + // 2016-03-12:Sat + + // current at before DST(-0800), last will be at before DST + { + Instant currentScheduleTime = instant("2016-03-12 00:00:00 -0800"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-05 00:00:00 -0800"), + instant("2016-03-05 17:15:00 -0800")))); + } + + // current at DST(-0700), last will be at DST + { + Instant currentScheduleTime2 = instant("2016-03-26 00:00:00 -0700"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime2), + is(ScheduleTime.of( + instant("2016-03-19 00:00:00 -0700"), + instant("2016-03-19 17:15:00 -0700")))); + } + + // current at DST(-0700), last will be at before DST(-0800) + { + Instant currentScheduleTime3 = instant("2016-03-19 00:00:00 -0700"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime3), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 17:15:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeMisc() + { + // current schedule time does not comply with hourly>'s one = 'YYYY-MM-DD 00:00:00' + // 2016-03-13:Sun + { + Instant currentScheduleTime = instant("2016-03-13 12:34:56 -0700"); + assertThat( + newScheduler("Sat,17:15:00", "America/Los_Angeles").lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-12 00:00:00 -0800"), + instant("2016-03-12 17:15:00 -0800")))); + } + } + + @Test + public void lastScheduleTimeStartEnd() + { + // lastScheduleTime calculation ignore start/end + { + Instant currentScheduleTime = instant("2016-02-10 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-03 00:00:00 +0900"), + instant("2016-02-03 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-02 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-02-24 00:00:00 +0900"), + instant("2016-02-24 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-03-09 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-03-02 00:00:00 +0900"), + instant("2016-03-02 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-06-01 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-05-25 00:00:00 +0900"), + instant("2016-05-25 17:15:00 +0900")))); + } + { + Instant currentScheduleTime = instant("2016-06-08 00:00:00 +0900"); + assertThat( + newScheduler("Wed,17:15:00", "Asia/Tokyo", Optional.of("2016-03-01"), Optional.of("2016-05-31")).lastScheduleTime(currentScheduleTime), + is(ScheduleTime.of( + instant("2016-06-01 00:00:00 +0900"), + instant("2016-06-01 17:15:00 +0900")))); + } + } +}