/* * (c) Rob Gordon 2005 */ package org.oddjob.jobs.structural; import junit.framework.TestCase; import org.apache.log4j.Logger; import org.oddjob.FailedToStopException; import org.oddjob.Oddjob; import org.oddjob.OddjobComponentResolver; import org.oddjob.OddjobLookup; import org.oddjob.Resetable; import org.oddjob.Stateful; import org.oddjob.Stoppable; import org.oddjob.arooa.convert.ArooaConversionException; import org.oddjob.arooa.reflect.ArooaPropertyException; import org.oddjob.arooa.standard.StandardArooaSession; import org.oddjob.arooa.xml.XMLConfiguration; import org.oddjob.framework.SimpleJob; import org.oddjob.persist.MapPersister; import org.oddjob.state.FlagState; import org.oddjob.state.JobState; import org.oddjob.state.MirrorState; import org.oddjob.state.ParentState; import org.oddjob.state.ServiceState; import org.oddjob.tools.ConsoleCapture; import org.oddjob.tools.StateSteps; /** * */ public class SequentialJobTest extends TestCase { private static final Logger logger = Logger.getLogger(SequentialJobTest.class); public static class OurJob extends SimpleJob { @Override protected int execute() throws Throwable { return 0; } } @Override protected void setUp() throws Exception { super.setUp(); logger.info("--------------------------------- " + getName() + " ----------------------------------"); } // an empty sequence must be ready. This is to agree with oddjob // which must also be ready when reset and empty. // this is really a bug in StatefulChildHelper. An empty sequence should // be ready until run and then be complete. I think. public void testEmpty() { SequentialJob test = new SequentialJob(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } // a sequence of just objects will always be complete when it runs public void testObject() { SequentialJob test = new SequentialJob(); test.setJobs(0, (new Object())); test.setJobs(1, (new Object())); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.COMPLETE, test.lastStateEvent().getState()); } public void testTriggers() { OurJob j1 = new OurJob(); MirrorState t1 = new MirrorState(); t1.setJob((Stateful) j1); t1.run(); OurJob j2 = new OurJob(); MirrorState t2 = new MirrorState(); t2.setJob((Stateful) j2); t2.run(); SequentialJob test = new SequentialJob(); test.setJobs(0, t1); test.setJobs(1, t2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); ((Runnable) j1).run(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); ((Runnable) j2).run(); assertEquals(ParentState.COMPLETE, test.lastStateEvent().getState()); ((Resetable) j2).hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testTwoRunnableJobs() { OurJob j1 = new OurJob(); OurJob j2 = new OurJob(); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); test.setJobs(1, j2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.COMPLETE, test.lastStateEvent().getState()); ((Resetable) j2).hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } /** * Test a mixture of Objects and jobs. */ public void testMixtureOfJobMirrorAndObject() { OurJob j1 = new OurJob(); Object j2 = new OurJob(); MirrorState t2 = new MirrorState(); t2.setJob((Stateful) j2); t2.run(); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); test.setJobs(1, t2); test.setJobs(2, new Object()); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); ((Runnable) j2).run(); assertEquals(ParentState.COMPLETE, test.lastStateEvent().getState()); test.hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testOneJobCompleteOneJobNotComplete() { FlagState j1 = new FlagState(); j1.setState(JobState.COMPLETE); FlagState j2 = new FlagState(); j2.setState(JobState.INCOMPLETE); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); test.setJobs(1, j2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.INCOMPLETE, test.lastStateEvent().getState()); test.hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testDependentProgression() { FlagState j1 = new FlagState(); j1.setState(JobState.INCOMPLETE); FlagState j2 = new FlagState(); j2.setState(JobState.COMPLETE); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); test.setJobs(1, j2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.INCOMPLETE, test.lastStateEvent().getState()); assertEquals(JobState.INCOMPLETE, j1.lastStateEvent().getState()); // j2 should not be attempted in dependent sequential job assertEquals(JobState.READY, j2.lastStateEvent().getState()); test.hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testIndependentProgression() { FlagState j1 = new FlagState(); j1.setState(JobState.INCOMPLETE); FlagState j2 = new FlagState(); j2.setState(JobState.COMPLETE); SequentialJob test = new SequentialJob(); test.setIndependent(true); test.setJobs(0, j1); test.setJobs(1, j2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.INCOMPLETE, test.lastStateEvent().getState()); assertEquals(JobState.INCOMPLETE, j1.lastStateEvent().getState()); // j2 should be attempted and complete in independent sequential job assertEquals(JobState.COMPLETE, j2.lastStateEvent().getState()); test.hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testException() { FlagState j1 = new FlagState(); j1.setState(JobState.COMPLETE); FlagState j2 = new FlagState(); j2.setState(JobState.EXCEPTION); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); test.setJobs(1, j2); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.run(); assertEquals(ParentState.EXCEPTION, test.lastStateEvent().getState()); test.hardReset(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); } public void testWhenSequentialJobDestroyedStateIsDestroyed() { FlagState j1 = new FlagState(); j1.setState(JobState.COMPLETE); SequentialJob test = new SequentialJob(); test.setJobs(0, j1); StateSteps sequentialState = new StateSteps(test); sequentialState.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.COMPLETE); test.run(); sequentialState.checkNow(); sequentialState.startCheck(ParentState.COMPLETE, ParentState.DESTROYED); test.destroy(); sequentialState.checkNow(); } public void testStatesWhenOddjobDestroyed() throws ArooaPropertyException, ArooaConversionException { String xml = "<oddjob>" + " <job>" + " <sequential id='sequential'>" + " <jobs>" + " <state:flag xmlns:state='http://rgordon.co.uk/oddjob/state'/>" + " </jobs>" + " </sequential>" + " </job>" + "</oddjob>"; Oddjob oddjob = new Oddjob(); oddjob.setConfiguration(new XMLConfiguration("XML", xml)); oddjob.run(); Stateful sequential = new OddjobLookup(oddjob).lookup( "sequential", Stateful.class); StateSteps state = new StateSteps(sequential); state.startCheck(ParentState.COMPLETE, ParentState.DESTROYED); oddjob.destroy(); state.checkNow(); } public static class MyService { public void start() {} public void stop() {} } public void testAServiceAndAJob() throws FailedToStopException { Object service = new OddjobComponentResolver().resolve( new MyService(), new StandardArooaSession()); FlagState job = new FlagState(); SequentialJob test = new SequentialJob(); test.setJobs(0, service); test.setJobs(0, job); StateSteps states = new StateSteps(test); states.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.STARTED); test.run(); states.checkNow(); assertEquals(JobState.COMPLETE, job.lastStateEvent().getState()); states.startCheck(ParentState.STARTED, ParentState.COMPLETE); test.stop(); states.checkNow(); } public void testTwoServices() throws FailedToStopException { Object service1 = new OddjobComponentResolver().resolve( new MyService(), new StandardArooaSession()); Object service2 = new OddjobComponentResolver().resolve( new MyService(), new StandardArooaSession()); SequentialJob test = new SequentialJob(); test.setJobs(0, service1); test.setJobs(0, service2); StateSteps states = new StateSteps(test); states.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.STARTED); test.run(); states.checkNow(); assertEquals(ServiceState.STARTED, ((Stateful) service1).lastStateEvent().getState()); assertEquals(ServiceState.STARTED, ((Stateful) service2).lastStateEvent().getState()); // Stop each service. Sequential should go to complete // only when both are stopped. states.startCheck(ParentState.STARTED, ParentState.COMPLETE); ((Stoppable) service1).stop(); assertEquals(ParentState.STARTED, test.lastStateEvent().getState()); ((Stoppable) service2).stop(); states.checkNow(); // Check that starting a service sequential reflects started. states.startCheck(ParentState.COMPLETE, ParentState.READY, ParentState.ACTIVE, ParentState.STARTED); ((Resetable) service1).hardReset(); ((Runnable) service1).run(); states.checkNow(); // Check stopping sequential. states.startCheck(ParentState.STARTED, ParentState.COMPLETE); test.stop(); states.checkNow(); } public void testNestedSequentials() throws FailedToStopException { Object service = new OddjobComponentResolver().resolve( new MyService(), new StandardArooaSession()); FlagState job1 = new FlagState(); SequentialJob sequential1 = new SequentialJob(); sequential1.setJobs(0, service); sequential1.setJobs(0, job1); SequentialJob sequential2 = new SequentialJob(); FlagState job2 = new FlagState(); sequential2.setJobs(0, job2); SequentialJob test = new SequentialJob(); test.setJobs(0, sequential1); test.setJobs(1, sequential2); StateSteps states = new StateSteps(sequential1); states.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.STARTED); test.run(); states.checkNow(); assertEquals(JobState.COMPLETE, job1.lastStateEvent().getState()); states.startCheck(ParentState.STARTED, ParentState.COMPLETE); test.stop(); states.checkNow(); } public void testExample() { Oddjob oddjob = new Oddjob(); oddjob.setConfiguration(new XMLConfiguration( "org/oddjob/jobs/structural/SimpleSequentialExample.xml", getClass().getClassLoader())); StateSteps steps = new StateSteps(oddjob); steps.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.COMPLETE); ConsoleCapture console = new ConsoleCapture(); try (ConsoleCapture.Close close = console.captureConsole()) { oddjob.run(); } steps.checkNow(); console.dump(logger); String[] lines = console.getLines(); assertEquals(2, lines.length); assertEquals("This runs first.", lines[0].trim()); assertEquals("This runs after.", lines[1].trim()); oddjob.destroy(); } public void testPersistence() throws ArooaPropertyException, ArooaConversionException { String xml = "<oddjob>" + " <job>" + " <sequential id='seq'>" + " <jobs>" + " <state:flag xmlns:state='http://rgordon.co.uk/oddjob/state'/>" + " </jobs>" + " </sequential>" + " </job>" + "</oddjob>"; MapPersister persister = new MapPersister(); { Oddjob oddjob1 = new Oddjob(); oddjob1.setConfiguration(new XMLConfiguration("XML", xml)); oddjob1.setPersister(persister); oddjob1.run(); assertEquals(ParentState.COMPLETE, oddjob1.lastStateEvent().getState()); oddjob1.destroy(); } { Oddjob oddjob2 = new Oddjob(); oddjob2.setConfiguration(new XMLConfiguration("XML", xml)); oddjob2.setPersister(persister); oddjob2.load(); assertEquals(ParentState.READY, oddjob2.lastStateEvent().getState()); OddjobLookup lookup = new OddjobLookup(oddjob2); Stateful seq = lookup.lookup("seq", Stateful.class); assertEquals(ParentState.COMPLETE, seq.lastStateEvent().getState()); } } public void testPersistenceWhenTransient() throws ArooaPropertyException, ArooaConversionException { String xml = "<oddjob>" + " <job>" + " <sequential id='seq' transient='true'>" + " <jobs>" + " <state:flag xmlns:state='http://rgordon.co.uk/oddjob/state'/>" + " </jobs>" + " </sequential>" + " </job>" + "</oddjob>"; MapPersister persister = new MapPersister(); { Oddjob oddjob1 = new Oddjob(); oddjob1.setConfiguration(new XMLConfiguration("XML", xml)); oddjob1.setPersister(persister); oddjob1.run(); assertEquals(ParentState.COMPLETE, oddjob1.lastStateEvent().getState()); oddjob1.destroy(); } { Oddjob oddjob2 = new Oddjob(); oddjob2.setConfiguration(new XMLConfiguration("XML", xml)); oddjob2.setPersister(persister); oddjob2.load(); assertEquals(ParentState.READY, oddjob2.lastStateEvent().getState()); OddjobLookup lookup = new OddjobLookup(oddjob2); Stateful seq = lookup.lookup("seq", Stateful.class); assertEquals(ParentState.READY, seq.lastStateEvent().getState()); } } }