/*
* (c) Rob Gordon 2005
*/
package org.oddjob.scheduling;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.oddjob.FailedToStopException;
import org.oddjob.MockOddjobExecutors;
import org.oddjob.MockStateful;
import org.oddjob.Oddjob;
import org.oddjob.OddjobLookup;
import org.oddjob.Resetable;
import org.oddjob.Stateful;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.types.ArooaObject;
import org.oddjob.arooa.utils.DateHelper;
import org.oddjob.arooa.xml.XMLConfiguration;
import org.oddjob.framework.SimpleJob;
import org.oddjob.images.IconHelper;
import org.oddjob.jobs.WaitJob;
import org.oddjob.persist.MapPersister;
import org.oddjob.schedules.Interval;
import org.oddjob.schedules.IntervalTo;
import org.oddjob.schedules.Schedule;
import org.oddjob.schedules.ScheduleContext;
import org.oddjob.schedules.SimpleInterval;
import org.oddjob.schedules.SimpleScheduleResult;
import org.oddjob.schedules.schedules.CountSchedule;
import org.oddjob.schedules.schedules.DailySchedule;
import org.oddjob.schedules.schedules.DateSchedule;
import org.oddjob.schedules.schedules.IntervalSchedule;
import org.oddjob.schedules.schedules.NowSchedule;
import org.oddjob.schedules.schedules.TimeSchedule;
import org.oddjob.scheduling.state.TimerState;
import org.oddjob.state.FlagState;
import org.oddjob.state.JobState;
import org.oddjob.state.ParentState;
import org.oddjob.state.StateEvent;
import org.oddjob.state.StateListener;
import org.oddjob.tools.IconSteps;
import org.oddjob.tools.ManualClock;
import org.oddjob.tools.OddjobTestHelper;
import org.oddjob.tools.OurDirs;
import org.oddjob.tools.StateSteps;
/**
*
*/
public class TimerTest extends TestCase {
private static final Logger logger = Logger.getLogger(TimerTest.class);
protected void setUp() {
logger.debug("=============== " + getName() + " ===================");
}
private class OurJob extends MockStateful
implements Runnable, Resetable {
int resets;
final List<StateListener> listeners = new ArrayList<StateListener>();
public void addStateListener(StateListener listener) {
listeners.add(listener);
listener.jobStateChange(new StateEvent(this, JobState.READY));
}
public void removeStateListener(StateListener listener) {
listeners.remove(listener);
}
public void run() {
List<StateListener> copy = new ArrayList<StateListener>(listeners);
for (StateListener listener: copy) {
listener.jobStateChange(new StateEvent(this, JobState.EXECUTING));
listener.jobStateChange(new StateEvent(this, JobState.COMPLETE));
}
}
public boolean hardReset() {
++resets;
return true;
}
public boolean softReset() {
throw new RuntimeException("Unexpected.");
}
}
private class OurScheduledExecutorService extends MockScheduledExecutorService {
Runnable runnable;
long delay;
ScheduledFuture<Void> future = new MockScheduledFuture<Void>();
public ScheduledFuture<?> schedule(Runnable runnable, long delay,
TimeUnit unit) {
OurScheduledExecutorService.this.delay = delay;
OurScheduledExecutorService.this.runnable = runnable;
return future;
}
};
public void testSimpleNonRepeatingSchedule()
throws Exception {
DateSchedule schedule = new DateSchedule();
schedule.setOn("2020-12-25");
OurJob ourJob = new OurJob();
ManualClock clock = new ManualClock("2020-12-24");
Timer test = new Timer();
test.setSchedule(schedule);
test.setJob(ourJob);
test.setHaltOnFailure(true);
test.setClock(clock);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
StateSteps timerStates = new StateSteps(test);
timerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
IconSteps timerIcons = new IconSteps(test);
timerIcons.startCheck(IconHelper.STARTABLE, IconHelper.EXECUTING,
IconHelper.STARTED);
test.run();
timerStates.checkNow();
timerIcons.checkNow();
Date expected = DateHelper.parseDate("2020-12-25");
assertEquals(expected, test.getNextDue());
assertEquals(expected, test.getCurrent().getFromDate());
assertEquals(24 * 60 * 60 * 1000L, oddjobServices.delay);
timerStates.startCheck(TimerState.STARTED, TimerState.ACTIVE,
TimerState.COMPLETE);
timerIcons.startCheck(IconHelper.STARTED, IconHelper.ACTIVE,
IconHelper.COMPLETE);
// Time passes... Executor runs job.
oddjobServices.delay = -1;
oddjobServices.runnable.run();
oddjobServices.runnable = null;
assertNull(null, test.getNextDue());
assertNull(null, test.getCurrent());
assertEquals(expected, test.getLastDue());
assertEquals(-1, oddjobServices.delay);
assertEquals(1, ourJob.resets);
timerStates.checkNow();
timerIcons.checkNow();
//
// Check reset and run again works as expected.
clock.setDateText("2020-12-25 00:00:01");
timerStates.startCheck(TimerState.COMPLETE, TimerState.STARTABLE);
timerIcons.startCheck(IconHelper.COMPLETE, IconHelper.STARTABLE);
test.hardReset();
timerStates.checkNow();
timerIcons.checkNow();
timerStates.startCheck(TimerState.STARTABLE,
TimerState.STARTING, TimerState.ACTIVE);
timerIcons.startCheck(IconHelper.STARTABLE, IconHelper.EXECUTING,
IconHelper.ACTIVE);
test.run();
timerStates.checkNow();
timerIcons.checkNow();
assertEquals(expected, test.getNextDue());
assertEquals(expected, test.getCurrent().getFromDate());
assertEquals(0L, oddjobServices.delay);
timerStates.startCheck(TimerState.ACTIVE,
TimerState.COMPLETE);
timerIcons.startCheck(IconHelper.ACTIVE,
IconHelper.COMPLETE);
// Time has passed... Executor would run job immediately.
oddjobServices.delay = -1;
oddjobServices.runnable.run();
oddjobServices.runnable = null;
assertNull(null, test.getNextDue());
assertNull(null, test.getCurrent());
assertEquals(expected, test.getLastDue());
assertEquals(-1, oddjobServices.delay);
assertEquals(3, ourJob.resets);
timerStates.checkNow();
timerIcons.checkNow();
//
// Destroy
test.setJob(null);
test.destroy();
assertEquals(0, ourJob.listeners.size());
}
public void testRecurringScheduleWhenStopped() throws ParseException {
FlagState job = new FlagState();
job.setState(JobState.COMPLETE);
DailySchedule time = new DailySchedule();
time.setFrom("14:45");
time.setTo("14:55");
ManualClock clock = new ManualClock("2009-02-10 14:50");
Timer test = new Timer();
test.setSchedule(time);
test.setClock(clock);
test.setJob(job);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertNotNull(oddjobServices.runnable);
assertEquals(0, oddjobServices.delay);
oddjobServices.runnable.run();
Date expectedNextDue = DateHelper.parseDateTime(
"2009-02-11 14:45");
assertEquals(expectedNextDue, test.getNextDue());
assertEquals(expectedNextDue.getTime() -clock.getDate().getTime(),
oddjobServices.delay);
}
public void testOverdueSchedule() throws ParseException {
FlagState job = new FlagState();
job.setState(JobState.COMPLETE);
DailySchedule time = new DailySchedule();
time.setAt("12:00");
ManualClock clock = new ManualClock("2009-03-02 14:00");
Timer test = new Timer();
test.setSchedule(time);
test.setClock(clock);
test.setJob(job);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertNotNull(oddjobServices.runnable);
assertEquals(22 * 60 * 60 * 1000, oddjobServices.delay);
// simulate job longer than next due;
clock.setDateText("2009-03-04 13:00");
oddjobServices.runnable.run();
assertEquals(0, oddjobServices.delay);
// next one runs quick.
clock.setDateText("2009-03-04 18:00");
oddjobServices.runnable.run();
assertEquals(18 * 60 * 60 * 1000, oddjobServices.delay);
}
public void testSkipMissedSchedule() throws ParseException {
FlagState job = new FlagState();
job.setState(JobState.COMPLETE);
DailySchedule time = new DailySchedule();
time.setAt("12:00");
ManualClock clock = new ManualClock("2009-03-02 14:00");
Timer test = new Timer();
test.setSchedule(time);
test.setClock(clock);
test.setJob(job);
test.setSkipMissedRuns(true);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertNotNull(oddjobServices.runnable);
assertEquals(22 * 60 * 60 * 1000, oddjobServices.delay);
// simulate job longer than next due;
clock.setDateText("2009-03-04 13:00");
oddjobServices.runnable.run();
// next one runs the next day.
assertEquals(23 * 60 * 60 * 1000, oddjobServices.delay);
}
public void testHaltOnFailure() throws ParseException {
FlagState job = new FlagState();
job.setState(JobState.INCOMPLETE);
TimeSchedule time = new TimeSchedule();
time.setFrom("14:45");
time.setTo("14:55");
ManualClock clock = new ManualClock("2009-02-10 14:50");
Timer test = new Timer();
test.setSchedule(time);
test.setClock(clock);
test.setHaltOnFailure(true);
test.setJob(job);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertNotNull(oddjobServices.runnable);
assertEquals(0, oddjobServices.delay);
oddjobServices.delay = -1;
oddjobServices.runnable.run();
assertEquals(-1, oddjobServices.delay);
assertEquals(null, test.getNextDue());
assertEquals(TimerState.INCOMPLETE, test.lastStateEvent().getState());
}
public void testTimeZone()
throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
DateSchedule schedule = new DateSchedule();
schedule.setOn("2020-06-21");
DailySchedule daily = new DailySchedule();
daily.setAt("10:00");
schedule.setRefinement(daily);
OurJob ourJob = new OurJob();
Timer test = new Timer();
test.setSchedule(schedule);
test.setJob(ourJob);
test.setTimeZone("GMT+8");
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertEquals(DateHelper.parseDateTime("2020-06-21 02:00"),
test.getNextDue());
TimeZone.setDefault(null);
}
public void testSerialize() throws Exception {
FlagState sample = new FlagState();
sample.setState(JobState.COMPLETE);
Timer test = new Timer();
IntervalSchedule interval = new IntervalSchedule();
interval.setInterval("00:00:05");
CountSchedule count = new CountSchedule();
count.setCount(2);
count.setRefinement(interval);
ManualClock clock = new ManualClock("2009-02-10 14:30");
test.setSchedule(count);
test.setJob(sample);
test.setClock(clock);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertEquals(0, oddjobServices.delay);
oddjobServices.runnable.run();
assertEquals(5000, oddjobServices.delay);
Timer copy = (Timer) OddjobTestHelper.copy(test);
copy.setClock(clock);
copy.setScheduleExecutorService(oddjobServices);
assertEquals(5000, oddjobServices.delay);
Runnable runnable = oddjobServices.runnable;
oddjobServices.runnable = null;
runnable.run();
assertNull(copy.getNextDue());
assertNull(oddjobServices.runnable);
}
public void testSerializeNotComplete() throws Exception {
FlagState sample = new FlagState();
sample.setState(JobState.INCOMPLETE);
Timer test = new Timer();
ManualClock clock = new ManualClock("2009-02-10 14:30");
test.setSchedule(new NowSchedule());
test.setJob(sample);
test.setClock(clock);
OurScheduledExecutorService oddjobServices = new OurScheduledExecutorService();
test.setScheduleExecutorService(oddjobServices);
test.run();
assertEquals(0, oddjobServices.delay);
oddjobServices.runnable.run();
Timer copy = (Timer) OddjobTestHelper.copy(test);
assertEquals(TimerState.STARTABLE, copy.lastStateEvent().getState());
assertEquals(DateHelper.parseDateTime("2009-02-10 14:30"),
test.getLastDue());
Interval expectedInterval = new SimpleInterval(
DateHelper.parseDateTime("2009-02-10 14:30"));
assertEquals(new SimpleScheduleResult(
expectedInterval, expectedInterval.getFromDate()),
test.getCurrent());
}
// Stub services for Stop test.
private class StubExecutorServicesForTestStop extends MockScheduledExecutorService {
boolean cancelled;
public ScheduledFuture<?> schedule(Runnable runnable, long delay,
TimeUnit unit) {
if (delay < 1) {
logger.info("** Service Executing [" + runnable + "] (" +
runnable.getClass().getName() + ")");
new Thread(runnable).start();
}
else {
logger.info("** Delay is [" + delay +
"], will never execute [" + runnable + "]");
}
return new MockScheduledFuture<Void>() {
public boolean cancel(boolean interrupt) {
cancelled = true;
return false;
}
};
}
};
private class ToggleJobs extends SimpleJob {
final AtomicInteger i = new AtomicInteger();
final Runnable[] jobs = {
new FlagState(), new WaitJob()
};
@Override
protected int execute() throws Throwable {
logger.info("Running job [" + i.get() + "]");
jobs[i.getAndIncrement()].run();
return 0;
}
}
public void testStopWhileANestedRetryJobIsExecutingASecondTime()
throws ParseException, InterruptedException, FailedToStopException {
final Timer test = new Timer();
test.setSchedule(new CountSchedule(2));
IntervalSchedule interval = new IntervalSchedule();
interval.setInterval("00:15");
Retry retry = new Retry();
retry.setSchedule(interval);
ToggleJobs child = new ToggleJobs();
retry.setJob(child);
test.setJob(retry);
StubExecutorServicesForTestStop services = new StubExecutorServicesForTestStop();
test.setScheduleExecutorService(services);
retry.setScheduleExecutorService(services);
StateSteps timerStates = new StateSteps(test);
timerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.ACTIVE);
StateSteps childStates = new StateSteps(child);
childStates.startCheck(JobState.READY, JobState.EXECUTING,
JobState.COMPLETE, JobState.READY, JobState.EXECUTING);
logger.info("** Starting timer.");
test.run();
childStates.checkWait();
timerStates.checkNow();
timerStates.startCheck(TimerState.ACTIVE,
TimerState.STARTABLE);
logger.info("** Stopping timer.");
test.stop();
timerStates.checkWait();
assertEquals(true, services.cancelled);
test.setJob(null);
retry.destroy();
test.destroy();
}
public void testStopBeforeTriggered() throws FailedToStopException {
class Executor extends MockScheduledExecutorService {
boolean canceled;
Runnable job;
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay,
TimeUnit unit) {
job = command;
return new MockScheduledFuture<Void>() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
assertEquals(false, mayInterruptIfRunning);
canceled = true;
job = null;
return true;
}
};
}
}
Executor executor = new Executor();
Timer test = new Timer();
test.setClock(new ManualClock("2011-09-30 00:10"));
test.setScheduleExecutorService(executor);
test.setJob(new FlagState());
TimeSchedule schedule = new TimeSchedule();
test.setSchedule(schedule);
StateSteps timerStates = new StateSteps(test);
timerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.ACTIVE);
IconSteps timerIcons = new IconSteps(test);
timerIcons.startCheck(IconHelper.STARTABLE, IconHelper.EXECUTING,
IconHelper.ACTIVE);
test.run();
timerStates.checkNow();
timerIcons.checkNow();
timerStates.startCheck(TimerState.ACTIVE, TimerState.STARTABLE);
timerIcons.startCheck(IconHelper.ACTIVE, IconHelper.STOPPING,
IconHelper.STARTABLE);
test.stop();
timerStates.checkNow();
timerIcons.checkNow();
assertEquals(true, executor.canceled);
timerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.ACTIVE);
test.run();
timerStates.checkNow();
timerStates.startCheck(TimerState.ACTIVE, TimerState.COMPLETE);
executor.job.run();
timerStates.checkNow();
test.destroy();
}
/**
* Schedule doesn't have to be serializable.
* @throws IOException
* @throws ClassNotFoundException
*/
public void testSerializeUnserializbleSchedule() throws IOException, ClassNotFoundException {
Timer test = new Timer();
test.setSchedule(new Schedule() {
public IntervalTo nextDue(ScheduleContext context) {
return null;
}
});
Timer copy = OddjobTestHelper.copy(test);
assertNull(copy.getSchedule());
}
public void testPersistedScheduleInOddjob() throws FailedToStopException, ArooaPropertyException, ArooaConversionException, InterruptedException, IOException, ParseException {
OurDirs dirs = new OurDirs();
File persistDir = dirs.relative("work/persisted-schedule");
if (persistDir.exists()) {
FileUtils.forceDelete(persistDir);
}
Oddjob oddjob1 = new Oddjob();
oddjob1.setFile(dirs.relative("test/conf/persisted-schedule.xml"));
oddjob1.setExport("clock", new ArooaObject(
new ManualClock("2011-03-09 06:30")));
oddjob1.setExport("work-dir", new ArooaObject(
dirs.relative("work")));
oddjob1.run();
assertEquals(ParentState.STARTED,
oddjob1.lastStateEvent().getState());
assertEquals(new SimpleInterval(
DateHelper.parseDateTime("2011-03-10 05:30"),
DateHelper.parseDateTime("2011-03-10 06:30")),
new OddjobLookup(oddjob1).lookup("persisted-schedule/schedule1.current"));
assertEquals(DateHelper.parseDateTime("2011-03-10 05:30"),
new OddjobLookup(oddjob1).lookup("persisted-schedule/schedule1.nextDue"));
oddjob1.stop();
assertEquals(ParentState.READY, oddjob1.lastStateEvent().getState());
oddjob1.destroy();
//
// Second run
Oddjob oddjob2 = new Oddjob();
oddjob2.setFile(dirs.relative("test/conf/persisted-schedule.xml"));
oddjob2.setExport("clock", new ArooaObject(
new ManualClock("2011-03-10 07:00")));
oddjob2.setExport("work-dir", new ArooaObject(
dirs.relative("work")));
oddjob2.load();
Oddjob innerOddjob2 = new OddjobLookup(oddjob2).lookup("persisted-schedule",
Oddjob.class);
innerOddjob2.load();
Stateful scheduledJob2 = new OddjobLookup(innerOddjob2).lookup("scheduled-job",
Stateful.class);
StateSteps scheduledJobState2 = new StateSteps(scheduledJob2);
scheduledJobState2.startCheck(JobState.READY, JobState.EXECUTING, JobState.COMPLETE);
oddjob2.run();
scheduledJobState2.checkWait();
String text2 = new OddjobLookup(oddjob2).lookup(
"persisted-schedule/scheduled-job.text", String.class);
assertEquals("Job schedule at 2011-03-10 05:30:00.000 " +
"but running at 2011-03-10 07:00:00.000",
text2);
oddjob2.stop();
assertEquals(ParentState.READY, oddjob2.lastStateEvent().getState());
oddjob2.destroy();
//
// Third run
Oddjob oddjob3 = new Oddjob();
oddjob3.setFile(dirs.relative("test/conf/persisted-schedule.xml"));
oddjob3.setExport("clock", new ArooaObject(
new ManualClock("2011-03-10 08:00")));
oddjob3.setExport("work-dir", new ArooaObject(
dirs.relative("work")));
oddjob3.run();
assertEquals(new SimpleInterval(
DateHelper.parseDateTime("2011-03-11 05:30"),
DateHelper.parseDateTime("2011-03-11 06:30")),
new OddjobLookup(oddjob3).lookup("persisted-schedule/schedule1.current"));
assertEquals(DateHelper.parseDateTime("2011-03-11 05:30"),
new OddjobLookup(oddjob3).lookup("persisted-schedule/schedule1.nextDue"));
String text3 = new OddjobLookup(oddjob3).lookup(
"persisted-schedule/scheduled-job.text", String.class);
assertEquals("Job schedule at 2011-03-10 05:30:00.000 " +
"but running at 2011-03-10 07:00:00.000",
text3);
oddjob3.stop();
assertEquals(ParentState.READY, oddjob3.lastStateEvent().getState());
oddjob3.destroy();
}
public void testTimerExample() throws ArooaPropertyException, ArooaConversionException, InterruptedException, FailedToStopException, ParseException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TimerExample.xml",
getClass().getClassLoader()));
oddjob.load();
assertEquals(ParentState.READY, oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
Timer timer = lookup.lookup("timer", Timer.class);
ManualClock clock = new ManualClock("2011-04-08 09:59:59.750");
timer.setClock(clock);
Stateful work = lookup.lookup("work", Stateful.class);
StateSteps workState = new StateSteps(work);
workState.startCheck(JobState.READY, JobState.EXECUTING, JobState.COMPLETE);
oddjob.run();
workState.checkWait();
assertEquals(DateHelper.parseDateTime("2011-04-11 10:00"),
timer.getNextDue());
String result = lookup.lookup("work.text", String.class);
assertEquals("Doing some work at 2011-04-08 10:00:00.000",
result);
oddjob.stop();
assertEquals(ParentState.READY, oddjob.lastStateEvent().getState());
//
// Run again.
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, work.lastStateEvent().getState());
assertEquals(DateHelper.parseDateTime("2011-04-11 10:00"),
timer.getNextDue());
oddjob.destroy();
}
public void testTimerOnceExample() throws ArooaPropertyException, ArooaConversionException, InterruptedException, FailedToStopException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TimerOnceExample.xml",
getClass().getClassLoader()));
oddjob.load();
assertEquals(ParentState.READY,
oddjob.lastStateEvent().getState());
Timer timer = (Timer) new OddjobLookup(oddjob).lookup("timer");
// on slow systems might go straight to ACTIVE.
timer.setClock(new ManualClock("2011-09-28 09:59:59.900"));
StateSteps states = new StateSteps(oddjob);
states.startCheck(ParentState.READY,
ParentState.EXECUTING,
ParentState.STARTED,
ParentState.ACTIVE,
ParentState.COMPLETE);
oddjob.run();
states.checkWait();
oddjob.destroy();
}
private class OurOddjobExecutor extends MockOddjobExecutors {
OurScheduledExecutorService executor =
new OurScheduledExecutorService();
@Override
public ScheduledExecutorService getScheduledExecutor() {
return executor;
}
@Override
public ExecutorService getPoolExecutor() {
return null;
}
}
public void testTimerStopJobExample() throws ArooaPropertyException, ArooaConversionException, InterruptedException, FailedToStopException {
OurOddjobExecutor executors = new OurOddjobExecutor();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TimerStopJobExample.xml",
getClass().getClassLoader()));
oddjob.setOddjobExecutors(executors);
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Stateful wait = lookup.lookup("long-job", Stateful.class);
Stateful timer = lookup.lookup("timer", Stateful.class);
StateSteps waitStates = new StateSteps(wait);
waitStates.startCheck(
JobState.READY,
JobState.EXECUTING);
StateSteps timerStates = new StateSteps(timer);
timerStates.startCheck(TimerState.STARTABLE,
TimerState.STARTING, TimerState.STARTED,
TimerState.ACTIVE, TimerState.COMPLETE);
Thread t = new Thread(oddjob);
t.start();
waitStates.checkWait();
assertTrue(executors.executor.delay > 9000);
StateSteps oddjobStates = new StateSteps(oddjob);
oddjobStates.startCheck(
ParentState.EXECUTING,
ParentState.STARTED,
ParentState.ACTIVE,
ParentState.COMPLETE);
executors.executor.runnable.run();
timerStates.checkWait();
// We can't guarantee order because timer might complete before
// sequential starts reflecting child states.
// states.checkWait();
t.join();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
oddjob.destroy();
}
public void testTimerCrashPersistance() {
String xml =
"<oddjob>" +
" <job>" +
" <scheduling:timer id='timer' xmlns:scheduling='http://rgordon.co.uk/oddjob/scheduling'>" +
" <schedule>" +
" <schedules:daily at='07:00' xmlns:schedules='http://rgordon.co.uk/oddjob/schedules'/>" +
" </schedule>" +
" <clock>" +
" <value value='${clock}'/>" +
" </clock>" +
" <job>" +
" <echo>Hi</echo>" +
" </job>" +
" </scheduling:timer>" +
" </job>" +
"</oddjob>";
OurOddjobExecutor executors1 = new OurOddjobExecutor();
MapPersister persister = new MapPersister();
Oddjob oddjob1 = new Oddjob();
oddjob1.setConfiguration(new XMLConfiguration("XML", xml));
oddjob1.setExport("clock", new ArooaObject(
new ManualClock("2011-12-23 07:00")));
oddjob1.setOddjobExecutors(executors1);
oddjob1.setPersister(persister);
oddjob1.run();
assertEquals(ParentState.ACTIVE, oddjob1.lastStateEvent().getState());
assertEquals(0, executors1.executor.delay);
executors1.executor.runnable.run();
assertEquals(24 * 60 * 60 * 1000L, executors1.executor.delay);
OurOddjobExecutor executors2 = new OurOddjobExecutor();
Oddjob oddjob2 = new Oddjob();
oddjob2.setConfiguration(new XMLConfiguration("XML", xml));
oddjob2.setExport("clock", new ArooaObject(
new ManualClock("2011-12-23 07:00")));
oddjob2.setOddjobExecutors(executors2);
oddjob2.setPersister(persister);
oddjob2.run();
assertEquals(24 * 60 * 60 * 1000L, executors2.executor.delay);
}
private class OurFuture extends MockScheduledFuture<Void> {
boolean cancelled;
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
this.cancelled = true;
return true;
}
}
public void testSetNextDue() throws ArooaPropertyException, ArooaConversionException, FailedToStopException, ParseException {
ManualClock clock = new ManualClock("2012-12-27 08:00");
OurFuture future = new OurFuture();
OurOddjobExecutor executors = new OurOddjobExecutor();
executors.executor.future = future;
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TimerSetNextDueExample.xml",
getClass().getClassLoader()));
oddjob.setOddjobExecutors(executors);
oddjob.setExport("clock", new ArooaObject(clock));
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
Timer test = lookup.lookup("timer", Timer.class);
assertEquals(DateHelper.parseDate("9999-12-31"), test.getNextDue());
assertNotNull(executors.executor.runnable);
assertEquals(252045619200000L, executors.executor.delay);
assertEquals(false, future.cancelled);
Runnable set = lookup.lookup("set", Runnable.class);
set.run();
assertEquals(DateHelper.parseDateTime("2012-12-27 08:02"),
test.getNextDue());
assertEquals((long) (2 * 60 * 1000), executors.executor.delay);
assertEquals(true, future.cancelled);
executors.executor.runnable.run();
assertEquals("Running at 9999-12-31 00:00:00.000", lookup.lookup("echo.text"));
oddjob.stop();
assertEquals(ParentState.COMPLETE, oddjob.lastStateEvent().getState());
oddjob.destroy();
}
public void testSetReshedule() throws ArooaPropertyException, ArooaConversionException, FailedToStopException, ParseException {
ManualClock clock = new ManualClock("2013-01-16 08:00");
OurFuture future = new OurFuture();
OurOddjobExecutor executors = new OurOddjobExecutor();
executors.executor.future = future;
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TimerSetRescheduleExample.xml",
getClass().getClassLoader()));
oddjob.setOddjobExecutors(executors);
oddjob.setExport("clock", new ArooaObject(clock));
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
Timer test = lookup.lookup("timer", Timer.class);
assertEquals(DateHelper.parseDateTime("2013-01-16 23:00:"),
test.getNextDue());
assertNotNull(executors.executor.runnable);
assertEquals(15 * 60 * 60 * 1000L, executors.executor.delay);
assertEquals(false, future.cancelled);
Runnable set = lookup.lookup("set", Runnable.class);
set.run();
assertEquals(DateHelper.parseDateTime("2013-01-17 23:00"),
test.getNextDue());
assertEquals((long) (39 * 60 * 60 * 1000L), executors.executor.delay);
assertEquals(true, future.cancelled);
executors.executor.runnable.run();
assertEquals("Running at 2013-01-17 23:00:00.000",
lookup.lookup("echo.text"));
oddjob.stop();
assertEquals(ParentState.READY, oddjob.lastStateEvent().getState());
oddjob.destroy();
}
}