package org.oddjob.jobs.structural;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import org.oddjob.FailedToStopException;
import org.oddjob.MockStateful;
import org.oddjob.Oddjob;
import org.oddjob.OddjobComponentResolver;
import org.oddjob.OddjobLookup;
import org.oddjob.Stateful;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.xml.XMLConfiguration;
import org.oddjob.framework.Service;
import org.oddjob.framework.StopWait;
import org.oddjob.jobs.WaitJob;
import org.oddjob.scheduling.DefaultExecutors;
import org.oddjob.scheduling.MockScheduledExecutorService;
import org.oddjob.scheduling.MockScheduledFuture;
import org.oddjob.state.FlagState;
import org.oddjob.state.IsAnyState;
import org.oddjob.state.JobState;
import org.oddjob.state.JobStateHandler;
import org.oddjob.state.ParentState;
import org.oddjob.state.ServiceState;
import org.oddjob.state.StateListener;
import org.oddjob.tools.ConsoleCapture;
import org.oddjob.tools.StateSteps;
import junit.framework.TestCase;
public class ParallelJobTest extends TestCase {
private static final Logger logger = Logger.getLogger(ParallelJobTest.class);
@Override
protected void setUp() throws Exception {
super.setUp();
logger.info("-------------------- " + getName() + " ----------------");
}
public void testThreeJobsWithDefaultExecutors() throws InterruptedException {
FlagState job1 = new FlagState(JobState.COMPLETE);
FlagState job2 = new FlagState(JobState.COMPLETE);
FlagState job3 = new FlagState(JobState.COMPLETE);
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.setExecutorService(defaultServices.getPoolExecutor());
test.setJobs(0, job1);
test.setJobs(1, job2);
test.setJobs(2, job3);
test.run();
steps.checkWait();
assertEquals(JobState.COMPLETE, job3.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job2.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job1.lastStateEvent().getState());
steps.startCheck(ParentState.COMPLETE, ParentState.READY);
test.hardReset();
assertEquals(JobState.READY, job1.lastStateEvent().getState());
assertEquals(JobState.READY, job2.lastStateEvent().getState());
assertEquals(JobState.READY, job3.lastStateEvent().getState());
steps.checkNow();
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.run();
steps.checkWait();
assertEquals(JobState.COMPLETE, job1.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job2.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job3.lastStateEvent().getState());
defaultServices.stop();
}
public void testOneObjectSetsStateComplete() throws InterruptedException {
Object job1 = new Object();
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING,
ParentState.COMPLETE);
test.setExecutorService(defaultServices.getPoolExecutor());
test.setJobs(0, job1);
test.run();
steps.checkWait();
steps.startCheck(ParentState.COMPLETE, ParentState.READY);
test.hardReset();
steps.checkNow();
steps.startCheck(ParentState.READY,
ParentState.EXECUTING,
ParentState.COMPLETE);
test.run();
steps.checkWait();
defaultServices.stop();
}
public void testTwoJobsAndAnObjectSetsStateComplete() throws InterruptedException {
Object job1 = new Object();
FlagState job2 = new FlagState(JobState.COMPLETE);
FlagState job3 = new FlagState(JobState.COMPLETE);
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.setExecutorService(defaultServices.getPoolExecutor());
test.setJobs(0, job1);
test.setJobs(1, job2);
test.setJobs(2, job3);
test.run();
steps.checkWait();
assertEquals(JobState.COMPLETE, job3.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job2.lastStateEvent().getState());
steps.startCheck(ParentState.COMPLETE, ParentState.READY);
test.hardReset();
assertEquals(JobState.READY, job2.lastStateEvent().getState());
assertEquals(JobState.READY, job3.lastStateEvent().getState());
steps.checkNow();
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.run();
// Sometimes the state goes to READY not ACTIVE - don't know why.
steps.checkWait();
assertEquals(JobState.COMPLETE, job2.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job3.lastStateEvent().getState());
defaultServices.stop();
}
public void testThrottledExecution() throws InterruptedException {
FlagState job1 = new FlagState(JobState.COMPLETE);
FlagState job2 = new FlagState(JobState.COMPLETE);
FlagState job3 = new FlagState(JobState.COMPLETE);
DefaultExecutors defaultServices = new DefaultExecutors();
defaultServices.setPoolSize(1);
ParallelJob test = new ParallelJob();
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.setExecutorService(defaultServices.getPoolExecutor());
test.setJobs(0, job1);
test.setJobs(0, job2);
test.setJobs(0, job3);
test.run();
steps.checkWait();
assertEquals(JobState.COMPLETE, job3.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job2.lastStateEvent().getState());
assertEquals(JobState.COMPLETE, job1.lastStateEvent().getState());
}
public void testStopWithDefaultExecutorsAndOneJob() throws InterruptedException, FailedToStopException {
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
test.setExecutorService(defaultServices.getPoolExecutor());
WaitJob job = new WaitJob();
test.setJobs(0, job);
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE);
StateSteps waitState = new StateSteps(job);
waitState.startCheck(JobState.READY,
JobState.EXECUTING);
test.run();
steps.checkWait();
waitState.checkWait();
steps.startCheck(
ParentState.ACTIVE,
ParentState.COMPLETE);
test.stop();
steps.checkNow();
test.destroy();
defaultServices.stop();
}
private class NowExecutor extends MockScheduledExecutorService {
public Future<?> submit(Runnable runnable) {
runnable.run();
return new MockScheduledFuture<Void>();
}
}
private class DestroyJob extends MockStateful
implements Runnable {
JobStateHandler handler = new JobStateHandler(this);
public void addStateListener(StateListener listener) {
handler.addStateListener(listener);
}
public void removeStateListener(StateListener listener) {
handler.removeStateListener(listener);
}
public void run() {
handler.waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
handler.setState(JobState.COMPLETE);
handler.fireEvent();
}
});
}
void destroy() {
handler.waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
handler.setState(JobState.DESTROYED);
handler.fireEvent();
}
});
}
}
/**
* Child state changes before null is set as the child. Parallel job
* shouln't get that state.
* @throws InterruptedException
*/
public void testChildDestroyed() throws InterruptedException {
ParallelJob test = new ParallelJob();
test.setExecutorService(new NowExecutor());
DestroyJob destroy = new DestroyJob();
test.setJobs(0, destroy);
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
test.run();
steps.checkNow();
steps.startCheck(
ParentState.COMPLETE, ParentState.DESTROYED);
test.destroy();
test.setJobs(0, null);
destroy.destroy();
steps.checkNow();
}
public void testInOddjob() throws InterruptedException, FailedToStopException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/jobs/structural/SimpleParallelExample.xml",
getClass().getClassLoader()));
ConsoleCapture console = new ConsoleCapture();
try (ConsoleCapture.Close close = console.captureConsole()) {
oddjob.run();
new StopWait(oddjob).run();
}
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
console.dump(logger);
String[] lines = console.getLines();
assertEquals(2, lines.length);
Set<String> results = new HashSet<String>();
results.add(lines[0].trim());
results.add(lines[1].trim());
assertTrue(results.contains("This runs in parallel"));
assertTrue(results.contains("With this which could be displayed first!"));
oddjob.destroy();
}
public void testStopInOddjob() throws ArooaPropertyException, ArooaConversionException, InterruptedException, FailedToStopException {
String xml =
"<oddjob>" +
" <job>" +
" <parallel>" +
" <jobs>" +
" <wait id='wait1'/>" +
" <wait id='wait2'/>" +
" </jobs>" +
" </parallel>" +
" </job>" +
"</oddjob>";
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration("XML", xml));
oddjob.load();
StateSteps oddjobState = new StateSteps(oddjob);
oddjobState.startCheck(ParentState.READY, ParentState.EXECUTING,
ParentState.ACTIVE);
StateSteps wait1State = new StateSteps(new OddjobLookup(oddjob).lookup(
"wait1", Stateful.class));
wait1State.startCheck(JobState.READY, JobState.EXECUTING);
StateSteps wait2State = new StateSteps(new OddjobLookup(oddjob).lookup(
"wait2", Stateful.class));
wait2State.startCheck(JobState.READY, JobState.EXECUTING);
Thread t = new Thread(oddjob);
t.start();
wait1State.checkWait();
wait2State.checkWait();
oddjobState.checkWait();
oddjobState.startCheck(ParentState.ACTIVE,
ParentState.COMPLETE);
oddjob.stop();
oddjobState.checkNow();
oddjob.destroy();
}
public static class MyService implements Service {
public void start() {}
public void stop() {}
}
public void testParallelServices() throws FailedToStopException, InterruptedException {
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
test.setExecutorService(defaultServices.getPoolExecutor());
Object service1 = new OddjobComponentResolver().resolve(
new MyService(), null);
Object service2 = new OddjobComponentResolver().resolve(
new MyService(), null);
test.setJobs(0, (Runnable) service1);
test.setJobs(1, (Runnable) service2);
StateSteps parallelStates = new StateSteps(test);
parallelStates.startCheck(ParentState.READY, ParentState.EXECUTING,
ParentState.ACTIVE, ParentState.STARTED);
StateSteps service1States = new StateSteps((Stateful) service1);
service1States.startCheck(ServiceState.STARTABLE,
ServiceState.STARTING, ServiceState.STARTED);
StateSteps service2States = new StateSteps((Stateful) service2);
service2States.startCheck(ServiceState.STARTABLE,
ServiceState.STARTING, ServiceState.STARTED);
test.run();
parallelStates.checkWait();
service1States.checkWait();
service2States.checkWait();
parallelStates.startCheck(ParentState.STARTED, ParentState.COMPLETE);
service1States.startCheck(ServiceState.STARTED, ServiceState.STOPPED);
service2States.startCheck(ServiceState.STARTED, ServiceState.STOPPED);
test.stop();
service1States.checkNow();
service2States.checkNow();
parallelStates.checkNow();
defaultServices.stop();
}
public void testJoin() throws FailedToStopException, InterruptedException {
DefaultExecutors defaultServices = new DefaultExecutors();
ParallelJob test = new ParallelJob();
test.setJoin(true);
test.setExecutorService(defaultServices.getPoolExecutor());
Object service1 = new OddjobComponentResolver().resolve(
new MyService(), null);
Object service2 = new OddjobComponentResolver().resolve(
new MyService(), null);
test.setJobs(0, (Runnable) service1);
test.setJobs(1, (Runnable) service2);
StateSteps parallelStates = new StateSteps(test);
parallelStates.startCheck(ParentState.READY, ParentState.EXECUTING,
ParentState.STARTED);
StateSteps service1States = new StateSteps((Stateful) service1);
service1States.startCheck(ServiceState.STARTABLE,
ServiceState.STARTING, ServiceState.STARTED);
StateSteps service2States = new StateSteps((Stateful) service2);
service2States.startCheck(ServiceState.STARTABLE,
ServiceState.STARTING, ServiceState.STARTED);
test.run();
parallelStates.checkWait();
service1States.checkWait();
service2States.checkWait();
parallelStates.startCheck(ParentState.STARTED, ParentState.COMPLETE);
service1States.startCheck(ServiceState.STARTED, ServiceState.STOPPED);
service2States.startCheck(ServiceState.STARTED, ServiceState.STOPPED);
test.stop();
service1States.checkNow();
service2States.checkNow();
parallelStates.checkNow();
defaultServices.stop();
}
public void testEmpty() throws InterruptedException {
ParallelJob test = new ParallelJob();
test.setExecutorService(new NowExecutor());
StateSteps steps = new StateSteps(test);
steps.startCheck(ParentState.READY,
ParentState.EXECUTING,
ParentState.READY);
test.run();
steps.checkWait();
test.destroy();
}
public static class SlowToStartService {
public void start() throws InterruptedException {
Thread.sleep(100);
}
public void stop() {
}
}
public void testParallelServiceExample() throws InterruptedException, FailedToStopException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/jobs/structural/ParallelServicesExample.xml",
getClass().getClassLoader()));
StateSteps oddjobStates = new StateSteps(oddjob);
oddjobStates.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.STARTED);
ConsoleCapture console = new ConsoleCapture();
try (ConsoleCapture.Close close = console.captureConsole()) {
oddjob.run();
oddjobStates.checkWait();
}
console.dump(logger);
String[] lines = console.getLines();
assertEquals(1, lines.length);
assertEquals("The lights are on and the machine goes ping.",
lines[0].trim());
oddjobStates.startCheck(ParentState.STARTED, ParentState.COMPLETE);
oddjob.stop();
oddjobStates.checkNow();
oddjob.destroy();
}
public void testParallelServiceThatCompletesExample()
throws InterruptedException, FailedToStopException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/jobs/structural/ParallelServicesExample2.xml",
getClass().getClassLoader()));
StateSteps oddjobStates = new StateSteps(oddjob);
oddjobStates.startCheck(ParentState.READY,
ParentState.EXECUTING, ParentState.ACTIVE,
ParentState.COMPLETE);
ConsoleCapture console = new ConsoleCapture();
try (ConsoleCapture.Close close = console.captureConsole()) {
oddjob.run();
oddjobStates.checkWait();
}
console.dump(logger);
String[] lines = console.getLines();
assertEquals(1, lines.length);
assertEquals("The lights are on and the machine goes ping.",
lines[0].trim());
oddjob.destroy();
}
}