/*
* Copyright 2006-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.jsr.job.flow;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.job.flow.State;
import org.springframework.batch.core.job.flow.StateSupport;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.batch.core.job.flow.support.StateTransition;
import org.springframework.batch.core.job.flow.support.state.DecisionState;
import org.springframework.batch.core.job.flow.support.state.EndState;
import org.springframework.batch.core.job.flow.support.state.FlowState;
import org.springframework.batch.core.job.flow.support.state.SplitState;
import org.springframework.batch.core.job.flow.support.state.StepState;
import org.springframework.batch.core.jsr.JsrStepExecution;
import org.springframework.batch.core.jsr.job.flow.support.JsrFlow;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.core.step.StepSupport;
import javax.batch.api.Decider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* @author Dave Syer
* @author Michael Minella
*/
public class JsrFlowJobTests {
private JsrFlowJob job;
private JobExecution jobExecution;
private JobRepository jobRepository;
private JobExplorer jobExplorer;
private boolean fail = false;
private JobExecutionDao jobExecutionDao;
@Before
public void setUp() throws Exception {
job = new JsrFlowJob();
MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean();
jobRepositoryFactory.afterPropertiesSet();
jobExecutionDao = jobRepositoryFactory.getJobExecutionDao();
jobRepository = jobRepositoryFactory.getObject();
job.setJobRepository(jobRepository);
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory);
jobExplorerFactory.afterPropertiesSet();
jobExplorer = jobExplorerFactory.getObject();
job.setJobExplorer(jobExplorer);
}
@Test
public void testGetSteps() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
assertEquals(2, job.getStepNames().size());
}
@Test
public void testTwoSteps() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
StepExecution stepExecution = getStepExecution(jobExecution, "step2");
assertEquals(ExitStatus.COMPLETED, stepExecution.getExitStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
}
@Test
public void testFailedStep() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StateSupport("step1", FlowExecutionStatus.FAILED),
"step2"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
StepExecution stepExecution = getStepExecution(jobExecution, "step2");
assertEquals(ExitStatus.COMPLETED, stepExecution.getExitStatus());
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
}
@Test
public void testFailedStepRestarted() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
State step2State = new StateSupport("step2") {
@Override
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
JobExecution jobExecution = executor.getJobExecution();
StepExecution stepExecution = jobExecution.createStepExecution(getName());
jobRepository.add(stepExecution);
if (fail) {
return FlowExecutionStatus.FAILED;
}
else {
return FlowExecutionStatus.COMPLETED;
}
}
};
transitions.add(StateTransition.createStateTransition(step2State, ExitStatus.COMPLETED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2State, ExitStatus.FAILED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
fail = true;
job.execute(jobExecution);
assertEquals(ExitStatus.FAILED, jobExecution.getExitStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
jobRepository.update(jobExecution);
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
fail = false;
job.execute(jobExecution);
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testStoppingStep() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
State state2 = new StateSupport("step2", FlowExecutionStatus.FAILED);
transitions.add(StateTransition.createStateTransition(state2, ExitStatus.FAILED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(state2, ExitStatus.COMPLETED.getExitCode(), "end1"));
transitions.add(StateTransition.createStateTransition(new EndState(FlowExecutionStatus.STOPPED, "end0"),
"step3"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step3")), "end2"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end2")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
assertEquals(2, jobExecution.getStepExecutions().size());
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
}
@Test
public void testInterrupted() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setStatus(BatchStatus.STOPPING);
jobRepository.update(stepExecution);
}
}), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
checkRepository(BatchStatus.STOPPED, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
}
@Test
public void testUnknownStatusStopsJob() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setStatus(BatchStatus.UNKNOWN);
stepExecution.setTerminateOnly();
jobRepository.update(stepExecution);
}
}), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.UNKNOWN, jobExecution.getStatus());
checkRepository(BatchStatus.UNKNOWN, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
}
@Test
public void testInterruptedSplit() throws Exception {
SimpleFlow flow = new JsrFlow("job");
SimpleFlow flow1 = new JsrFlow("flow1");
SimpleFlow flow2 = new JsrFlow("flow2");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
if (!stepExecution.getJobExecution().getExecutionContext().containsKey("STOPPED")) {
stepExecution.getJobExecution().getExecutionContext().put("STOPPED", true);
stepExecution.setStatus(BatchStatus.STOPPED);
jobRepository.update(stepExecution);
}
else {
fail("The Job should have stopped by now");
}
}
}), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow1.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow1.afterPropertiesSet();
flow2.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow2.afterPropertiesSet();
transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new SplitState(Arrays.<Flow> asList(flow1, flow2),
"split"), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
checkRepository(BatchStatus.STOPPED, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
assertEquals(1, jobExecution.getStepExecutions().size());
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
assertEquals(BatchStatus.STOPPED, stepExecution.getStatus());
}
}
@Test
public void testInterruptedException() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
throw new JobInterruptedException("Stopped");
}
}), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
checkRepository(BatchStatus.STOPPED, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
}
@Test
public void testInterruptedSplitException() throws Exception {
SimpleFlow flow = new JsrFlow("job");
SimpleFlow flow1 = new JsrFlow("flow1");
SimpleFlow flow2 = new JsrFlow("flow2");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
throw new JobInterruptedException("Stopped");
}
}), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow1.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow1.afterPropertiesSet();
flow2.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow2.afterPropertiesSet();
transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new SplitState(Arrays.<Flow> asList(flow1, flow2),
"split"), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
checkRepository(BatchStatus.STOPPED, ExitStatus.STOPPED);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(JobInterruptedException.class, jobExecution.getFailureExceptions().get(0).getClass());
}
@Test
public void testEndStateStopped() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "end"));
transitions.add(StateTransition
.createStateTransition(new EndState(FlowExecutionStatus.STOPPED, "end"), "step2"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
assertEquals(1, jobExecution.getStepExecutions().size());
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
}
public void testEndStateFailed() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "end"));
transitions
.add(StateTransition.createStateTransition(new EndState(FlowExecutionStatus.FAILED, "end"), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), ExitStatus.FAILED
.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")),
ExitStatus.COMPLETED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testEndStateStoppedWithRestart() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "end"));
transitions.add(StateTransition
.createStateTransition(new EndState(FlowExecutionStatus.STOPPED, "end"), "step2"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end1")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
// To test a restart we have to use the AbstractJob.execute()...
job.execute(jobExecution);
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
job.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testBranching() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
StepState step1 = new StepState(new StubStep("step1"));
transitions.add(StateTransition.createStateTransition(step1, "step2"));
transitions.add(StateTransition.createStateTransition(step1, "COMPLETED", "step3"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end1")));
StepState step3 = new StepState(new StubStep("step3"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.FAILED.getExitCode(), "end2"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.COMPLETED.getExitCode(), "end3"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end2")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end3")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.afterPropertiesSet();
job.doExecute(jobExecution);
StepExecution stepExecution = getStepExecution(jobExecution, "step2");
assertEquals(ExitStatus.COMPLETED, stepExecution.getExitStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
}
@Test
public void testBasicFlow() throws Throwable {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.execute(jobExecution);
if (!jobExecution.getAllFailureExceptions().isEmpty()) {
throw jobExecution.getAllFailureExceptions().get(0);
}
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
@Test
public void testDecisionFlow() throws Throwable {
SimpleFlow flow = new JsrFlow("job");
Decider decider = new Decider() {
@Override
public String decide(javax.batch.runtime.StepExecution[] executions)
throws Exception {
assertNotNull(executions);
return "SWITCH";
}
};
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "decision"));
StepState decision = new StepState(new StubDecisionStep("decision", decider));
transitions.add(StateTransition.createStateTransition(decision, "SWITCH", "step3"));
transitions.add(StateTransition.createStateTransition(decision, "step2"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end1")));
StepState step3 = new StepState(new StubStep("step3"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.FAILED.getExitCode(), "end2"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.COMPLETED.getExitCode(), "end3"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end2")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end3")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
job.doExecute(jobExecution);
StepExecution stepExecution = getStepExecution(jobExecution, "step3");
if (!jobExecution.getAllFailureExceptions().isEmpty()) {
throw jobExecution.getAllFailureExceptions().get(0);
}
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
assertEquals(3, jobExecution.getStepExecutions().size());
}
@Test
public void testDecisionFlowWithExceptionInDecider() throws Throwable {
SimpleFlow flow = new JsrFlow("job");
JobExecutionDecider decider = new JobExecutionDecider() {
@Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
assertNotNull(stepExecution);
throw new RuntimeException("Foo");
}
};
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "decision"));
DecisionState decision = new DecisionState(decider, "decision");
transitions.add(StateTransition.createStateTransition(decision, "step2"));
transitions.add(StateTransition.createStateTransition(decision, "SWITCH", "step3"));
StepState step2 = new StepState(new StubStep("step2"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end0"));
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end1")));
StepState step3 = new StepState(new StubStep("step3"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.FAILED.getExitCode(), "end2"));
transitions.add(StateTransition.createStateTransition(step3, ExitStatus.COMPLETED.getExitCode(), "end3"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end2")));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end3")));
flow.setStateTransitions(transitions);
job.setFlow(flow);
try {
job.execute(jobExecution);
}
finally {
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals("Foo", jobExecution.getAllFailureExceptions().get(0).getCause().getCause().getMessage());
}
}
@Test
public void testGetStepExists() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
Step step = job.getStep("step2");
assertNotNull(step);
assertEquals("step2", step.getName());
}
@Test
public void testGetStepExistsWithPrefix() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState("job.step", new StubStep("step")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.setName(flow.getName());
job.afterPropertiesSet();
Step step = job.getStep("step");
assertNotNull(step);
assertEquals("step", step.getName());
}
@Test
public void testGetStepNamesWithPrefix() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState("job.step", new StubStep("step")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.setName(flow.getName());
job.afterPropertiesSet();
assertEquals("[step]", job.getStepNames().toString());
}
@Test
public void testGetStepNotExists() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
Step step = job.getStep("foo");
assertNull(step);
}
@Test
public void testGetStepNotStepState() throws Exception {
SimpleFlow flow = new JsrFlow("job");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "step2"));
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
Step step = job.getStep("end0");
assertNull(step);
}
@Test
public void testGetStepNestedFlow() throws Exception {
SimpleFlow nested = new JsrFlow("nested");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
nested.setStateTransitions(transitions);
nested.afterPropertiesSet();
SimpleFlow flow = new JsrFlow("job");
transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "nested"));
transitions.add(StateTransition.createStateTransition(new FlowState(nested, "nested"), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
List<String> names = new ArrayList<String>(job.getStepNames());
Collections.sort(names);
assertEquals("[step1, step2]", names.toString());
}
@Test
public void testGetStepSplitFlow() throws Exception {
SimpleFlow flow = new JsrFlow("job");
SimpleFlow flow1 = new JsrFlow("flow1");
SimpleFlow flow2 = new JsrFlow("flow2");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
flow1.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow1.afterPropertiesSet();
transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step2")), "end1"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end1")));
flow2.setStateTransitions(new ArrayList<StateTransition>(transitions));
flow2.afterPropertiesSet();
transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new SplitState(Arrays.<Flow> asList(flow1, flow2),
"split"), "end2"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end2")));
flow.setStateTransitions(transitions);
flow.afterPropertiesSet();
job.setFlow(flow);
job.afterPropertiesSet();
List<String> names = new ArrayList<String>(job.getStepNames());
Collections.sort(names);
assertEquals("[step1, step2]", names.toString());
}
/**
* @author Dave Syer
*
*/
private class StubStep extends StepSupport {
private StubStep(String name) {
super(name);
}
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setExitStatus(ExitStatus.COMPLETED);
jobRepository.update(stepExecution);
}
}
/**
* @author Michael Minella
*
*/
private class StubDecisionStep extends StepSupport {
private Decider decider;
private StubDecisionStep(String name, Decider decider) {
super(name);
this.decider = decider;
}
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setStatus(BatchStatus.COMPLETED);
try {
stepExecution.setExitStatus(new ExitStatus(decider.decide(new javax.batch.runtime.StepExecution [] {new JsrStepExecution(stepExecution)})));
} catch (Exception e) {
throw new RuntimeException(e);
}
jobRepository.update(stepExecution);
}
}
/**
* @param jobExecution
* @param stepName
* @return the StepExecution corresponding to the specified step
*/
private StepExecution getStepExecution(JobExecution jobExecution, String stepName) {
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
if (stepExecution.getStepName().equals(stepName)) {
return stepExecution;
}
}
fail("No stepExecution found with name: [" + stepName + "]");
return null;
}
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
// because map DAO stores in memory, it can be checked directly
JobInstance jobInstance = jobExecution.getJobInstance();
JobExecution other = jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), other.getJobId());
assertEquals(status, other.getStatus());
if (exitStatus != null) {
assertEquals(exitStatus.getExitCode(), other.getExitStatus().getExitCode());
}
}
}