/*
* (c) Rob Gordon 2005
*/
package org.oddjob.scheduling;
import java.util.Date;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.oddjob.FailedToStopException;
import org.oddjob.Oddjob;
import org.oddjob.OddjobLookup;
import org.oddjob.Stateful;
import org.oddjob.arooa.ArooaParseException;
import org.oddjob.arooa.MockArooaSession;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.parsing.DragPoint;
import org.oddjob.arooa.parsing.DragTransaction;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.registry.ChangeHow;
import org.oddjob.arooa.registry.ComponentPool;
import org.oddjob.arooa.registry.MockComponentPool;
import org.oddjob.arooa.utils.DateHelper;
import org.oddjob.arooa.xml.XMLConfiguration;
import org.oddjob.framework.SimpleJob;
import org.oddjob.jobs.SequenceJob;
import org.oddjob.jobs.WaitJob;
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.StateConditions;
import org.oddjob.state.StateListener;
import org.oddjob.tools.OddjobTestHelper;
import org.oddjob.tools.StateSteps;
/**
*
*/
public class TriggerTest extends TestCase {
private static final Logger logger =
Logger.getLogger(TriggerTest.class);
@Override
protected void setUp() throws Exception {
super.setUp();
logger.debug("----------------- " + getName() + " -------------");
}
private class OurDependant extends SimpleJob {
private StateListener listenerCheck;
private JobState state;
public OurDependant() {
this(JobState.COMPLETE);
}
public OurDependant(JobState state) {
this.state = state;
}
// public void setState(JobState state) {
// this.state = state;
// }
@Override
protected int execute() throws Throwable {
switch (state) {
case COMPLETE:
return 0;
case INCOMPLETE:
return 1;
default:
throw new RuntimeException("Deliberate Exception.");
}
}
@Override
public void addStateListener(StateListener listener) {
assertNull(listenerCheck);
assertNotNull(listener);
this.listenerCheck = listener;
super.addStateListener(listener);
}
@Override
public void removeStateListener(StateListener listener) {
assertNotNull(listenerCheck);
assertEquals(listenerCheck, listener);
listenerCheck = null;
super.removeStateListener(listener);
}
}
private class OurJob extends SimpleJob {
private StateListener listenerCheck;
AtomicInteger ran = new AtomicInteger();
private JobState state = JobState.COMPLETE;
public void setState(JobState state) {
this.state = state;
}
@Override
protected int execute() throws Throwable {
ran.incrementAndGet();
switch (state) {
case COMPLETE:
return 0;
case INCOMPLETE:
return 1;
default:
throw new RuntimeException("Deliberate Exception.");
}
}
@Override
public void addStateListener(StateListener listener) {
assertNull(listenerCheck);
assertNotNull(listener);
this.listenerCheck = listener;
super.addStateListener(listener);
}
@Override
public void removeStateListener(StateListener listener) {
assertNotNull(listenerCheck);
assertEquals(listenerCheck, listener);
listenerCheck = null;
super.removeStateListener(listener);
}
}
public void testTriggerFiresButThenNotAgainOnSameState() throws Exception {
DefaultExecutors services = new DefaultExecutors();
OurJob job = new OurJob();
OurDependant dependant = new OurDependant();
Trigger test = new Trigger();
test.setOn(dependant);
test.setJob(job);
test.setNewOnly(true);
test.setExecutorService(services.getPoolExecutor());
StateSteps testState = new StateSteps(test);
testState.startCheck(TimerState.STARTABLE, TimerState.STARTING, TimerState.STARTED);
test.run();
testState.checkNow();
testState.startCheck(TimerState.STARTED, TimerState.ACTIVE,
TimerState.COMPLETE);
logger.info("** Running dependant.");
dependant.run();
testState.checkWait();
assertEquals(1, job.ran.get());
testState.startCheck(TimerState.COMPLETE, TimerState.STARTABLE);
job.hardReset();
testState.checkNow();
testState.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
logger.info("** Running trigger again.");
// trigger won't fire because event is the same.
test.run();
testState.checkNow();
assertEquals(1, job.ran.get());
testState.startCheck(TimerState.STARTED, TimerState.ACTIVE,
TimerState.COMPLETE);
while (new Date().equals(dependant.lastStateEvent().getTime())) {
// Note that sleeping for 1 millisecond is operating system
// dependent and there is no guarantee that it is a millisecond
// later after this operation - hence the while.
Thread.sleep(1);
logger.info("Slept until [" +
DateHelper.formatDateTime(new Date()) + "]");
}
logger.info("** Running dependant again.");
dependant.hardReset();
dependant.run();
testState.checkWait();
assertEquals(2, job.ran.get());
logger.info("Shutting down.");
services.stop();
}
public void testTriggerReflectsChildJobState() throws Exception {
final DefaultExecutors services = new DefaultExecutors();
OurJob job = new OurJob();
job.setState(JobState.EXCEPTION);
OurDependant depends = new OurDependant();
Trigger test = new Trigger();
test.setOn(depends);
test.setJob(job);
test.setExecutorService(services.getPoolExecutor());
StateSteps testState = new StateSteps(test);
testState.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
test.run();
testState.checkNow();
testState.startCheck(TimerState.STARTED, TimerState.ACTIVE,
TimerState.EXCEPTION);
depends.run();
testState.checkWait();
job.setState(JobState.INCOMPLETE);
depends.hardReset();
test.hardReset();
testState.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED, TimerState.ACTIVE, TimerState.INCOMPLETE);
test.run();
depends.run();
testState.checkWait();
services.stop();
}
public void testDestroyCycle() throws Exception {
final DefaultExecutors services = new DefaultExecutors();
OurJob job = new OurJob();
OurDependant depends = new OurDependant();
Trigger test = new Trigger();
test.setOn(depends);
test.setJob(job);
test.setExecutorService(services.getPoolExecutor());
StateSteps testState = new StateSteps(test);
testState.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
test.run();
depends.run();
testState.checkWait();
testState.startCheck(TimerState.COMPLETE, TimerState.STARTABLE,
TimerState.DESTROYED);
test.setJob(null);
job.destroy();
test.destroy();
depends.destroy();
testState.checkNow();
services.stop();
}
public void testStopBeforeTriggered() throws FailedToStopException {
class NeverRun extends SimpleJob {
@Override
protected int execute() throws Throwable {
throw new Exception("Shouldn't Run.");
}
}
Trigger test = new Trigger();
test.setOn(new NeverRun());
test.setJob(new NeverRun());
test.setExecutorService(new MockExecutorService());
StateSteps testStates = new StateSteps(test);
testStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
test.run();
testStates.checkNow();
testStates.startCheck(TimerState.STARTED, TimerState.STARTABLE);
test.stop();
testStates.checkNow();
}
private class OurOddjobServices extends MockScheduledExecutorService {
public Future<?> submit(Runnable runnable) {
runnable.run();
return new MockScheduledFuture<Void>();
}
};
private class SerializeSession extends MockArooaSession {
Object saved;
@Override
public ComponentPool getComponentPool() {
return new MockComponentPool() {
@Override
public void configure(Object component) {
}
@Override
public void save(Object component) {
saved = component;
}
};
}
}
public void testSerialize() throws Exception {
FlagState sample = new FlagState();
sample.setState(JobState.COMPLETE);
FlagState on = new FlagState();
on.setState(JobState.COMPLETE);
SerializeSession session = new SerializeSession();
Trigger test = new Trigger();
test.setArooaSession(session);
test.setExecutorService(new OurOddjobServices());
test.setOn(on);
test.setJob(sample);
test.setNewOnly(true);
StateSteps testStates = new StateSteps(test);
testStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
test.run();
on.run();
testStates.checkWait();
assertEquals(test, session.saved);
Trigger copy = (Trigger) OddjobTestHelper.copy(test);
assertEquals(TimerState.COMPLETE, copy.lastStateEvent().getState());
copy.setExecutorService(new OurOddjobServices());
copy.setOn(on);
copy.setJob(sample);
copy.hardReset();
while (new Date().equals(copy.lastStateEvent().getTime())) {
Thread.sleep(1);
logger.info("Slept until [" +
DateHelper.formatDateTime(new Date()) + "]");
}
StateSteps copyStates = new StateSteps(copy);
copyStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
copy.run();
copyStates.checkNow();
assertEquals(JobState.READY, sample.lastStateEvent().getState());
copyStates.startCheck(TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
on.hardReset();
on.run();
copyStates.checkWait();
assertEquals(JobState.COMPLETE, sample.lastStateEvent().getState());
}
public void testReset() throws Exception {
SequenceJob sequence = new SequenceJob();
sequence.setFrom(1);
FlagState on = new FlagState();
on.setState(JobState.INCOMPLETE);
Trigger test = new Trigger();
test.setExecutorService(new OurOddjobServices());
test.setOn(on);
test.setJob(sequence);
test.setState(StateConditions.INCOMPLETE);
test.setNewOnly(true);
StateSteps testStates = new StateSteps(test);
testStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED);
test.run();
testStates.checkNow();
testStates.startCheck(
TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
assertEquals(null, sequence.getCurrent());
on.run();
testStates.checkWait();
assertEquals(new Integer(1), sequence.getCurrent());
assertEquals(TimerState.COMPLETE, test.lastStateEvent().getState());
test.hardReset();
while (System.currentTimeMillis() == test.lastStateEvent().getTime().getTime()) {
Thread.sleep(1);
logger.info("Slept until [" +
DateHelper.formatDateTime(new Date()) + "]");
}
test.run();
assertEquals(TimerState.STARTED, test.lastStateEvent().getState());
on.hardReset();
assertEquals(JobState.READY, on.lastStateEvent().getState());
testStates.startCheck(
TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
on.run();
testStates.checkWait();
assertEquals(new Integer(2), sequence.getCurrent());
assertEquals(TimerState.COMPLETE, test.lastStateEvent().getState());
}
public void testNoChild() throws Exception {
FlagState on = new FlagState();
on.setState(JobState.INCOMPLETE);
Trigger test = new Trigger();
test.setExecutorService(new OurOddjobServices());
test.setOn(on);
test.setState(StateConditions.INCOMPLETE);
test.run();
assertEquals(TimerState.STARTED, test.lastStateEvent().getState());
on.run();
assertEquals(TimerState.STARTABLE, test.lastStateEvent().getState());
test.hardReset();
assertEquals(TimerState.STARTABLE, test.lastStateEvent().getState());
test.destroy();
}
public void testInOddjob() throws InterruptedException, ArooaPropertyException, ArooaConversionException {
String xml =
"<oddjob xmlns:si='http://rgordon.co.uk/oddjob/scheduling'" +
" id='this'>" +
" <job>" +
" <sequential>" +
" <jobs>" +
// " <rmireg/>" +
// " <server url='service:jmx:rmi://ignored/jndi/rmi://localhost/my-oddjob'" +
// " root='${this}'/>" +
" <si:trigger on='${thing1}' id='trigger'>" +
" <job>" +
" <echo id='stop'>Now you can stop.</echo>" +
" </job>" +
" </si:trigger>" +
" <folder>" +
" <jobs>" +
" <echo id='thing1'>Triggered!</echo>" +
" </jobs>" +
" </folder>" +
" </jobs>" +
" </sequential>" +
" </job>" +
"</oddjob>";
DefaultExecutors services = new DefaultExecutors();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration("XML", xml));
oddjob.setOddjobExecutors(services);
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Runnable runnable = lookup.lookup("thing1", Runnable.class);
Stateful trigger = lookup.lookup("trigger", Stateful.class);
StateSteps triggerStates = new StateSteps(trigger);
triggerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING,
TimerState.STARTED, TimerState.ACTIVE, TimerState.COMPLETE);
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
runnable.run();
triggerStates.checkWait();
assertEquals(ParentState.COMPLETE, oddjob.lastStateEvent().getState());
services.stop();
oddjob.destroy();
}
public void testCuttingTriggerJob() throws InterruptedException, ArooaParseException {
String xml =
"<oddjob xmlns:si='http://rgordon.co.uk/oddjob/scheduling'" +
" id='this'>" +
" <job>" +
" <sequential>" +
" <jobs>" +
" <si:trigger on='${thing1}' id='trigger'>" +
" <job>" +
" <echo id='stop'>Now you can stop</echo>" +
" </job>" +
" </si:trigger>" +
" <folder>" +
" <jobs>" +
" <echo id='thing1'>Triggered!</echo>" +
" </jobs>" +
" </folder>" +
" </jobs>" +
" </sequential>" +
" </job>" +
"</oddjob>";
DefaultExecutors services = new DefaultExecutors();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration("XML", xml));
oddjob.setOddjobExecutors(services);
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
Object on = new OddjobLookup(oddjob).lookup("thing1");
DragPoint drag = oddjob.provideConfigurationSession().dragPointFor(on);
DragTransaction trn = drag.beginChange(ChangeHow.FRESH);
drag.cut();
try {
trn.commit();
} catch (ArooaParseException e) {
trn.rollback();
throw e;
}
assertEquals(ParentState.EXCEPTION, oddjob.lastStateEvent().getState());
services.stop();
oddjob.destroy();
}
public void testSimpleExample() throws InterruptedException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TriggerSimple.xml",
getClass().getClassLoader()));
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
StateSteps states = new StateSteps(oddjob);
states.startCheck(ParentState.STARTED, ParentState.ACTIVE,
ParentState.COMPLETE);
OddjobLookup lookup = new OddjobLookup(oddjob);
Runnable important = (Runnable) lookup.lookup("important");
important.run();
states.checkWait();
oddjob.destroy();
}
public void testExample() throws InterruptedException {
DefaultExecutors services = new DefaultExecutors();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TriggerExample.xml",
getClass().getClassLoader()));
oddjob.setOddjobExecutors(services);
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Stateful test = (Stateful) lookup.lookup("trigger");
StateSteps testStates = new StateSteps(test);
testStates.startCheck(TimerState.STARTABLE,
TimerState.STARTING, TimerState.STARTED);
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
testStates.checkNow();
testStates.startCheck(TimerState.STARTED, TimerState.ACTIVE,
TimerState.COMPLETE);
Runnable thing1 = (Runnable) lookup.lookup("thing1");
thing1.run();
Runnable thing2 = (Runnable) lookup.lookup("thing2");
thing2.run();
testStates.checkWait();
assertEquals(ParentState.COMPLETE, oddjob.lastStateEvent().getState());
services.stop();
oddjob.destroy();
}
public void testCancelExample() throws InterruptedException {
DefaultExecutors services = new DefaultExecutors();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/scheduling/TriggerCancelExample.xml",
getClass().getClassLoader()));
oddjob.setOddjobExecutors(services);
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Stateful test = (Stateful) lookup.lookup("trigger");
StateSteps testStates = new StateSteps(test);
testStates.startCheck(TimerState.STARTABLE,
TimerState.STARTING, TimerState.STARTED);
oddjob.run();
assertEquals(ParentState.STARTED, oddjob.lastStateEvent().getState());
testStates.checkNow();
testStates.startCheck(TimerState.STARTED,
TimerState.COMPLETE);
Runnable ourJob = (Runnable) lookup.lookup("our-job");
ourJob.run();
testStates.checkWait();
assertEquals(ParentState.COMPLETE, oddjob.lastStateEvent().getState());
Stateful triggeredJob = (Stateful) lookup.lookup("triggered-job");
assertEquals(JobState.READY,
triggeredJob.lastStateEvent().getState());
services.stop();
oddjob.destroy();
}
public void testStop() throws InterruptedException, FailedToStopException {
DefaultExecutors services = new DefaultExecutors();
Trigger test = new Trigger();
test.setExecutorService(services.getPoolExecutor());
WaitJob wait = new WaitJob();
FlagState on = new FlagState();
test.setOn(on);
test.setJob(wait);
StateSteps waitState = new StateSteps(wait);
waitState.startCheck(JobState.READY, JobState.EXECUTING);
test.run();
on.run();
waitState.checkWait();
StateSteps testState = new StateSteps(test);
testState.startCheck(TimerState.ACTIVE,
TimerState.COMPLETE);
test.stop();
testState.checkWait();
services.stop();
}
}