IN PROGRESS - issue BATCH-264: Dependencies among jobs

Implement ConditionalJob (branching but not concurrent execution) and tidy up Abstract and SimpleJob a bit.
This commit is contained in:
dsyer
2008-10-15 14:23:15 +00:00
parent fa2b04a1db
commit c1a05e71a4
9 changed files with 892 additions and 35 deletions

View File

@@ -0,0 +1,221 @@
/*
* Copyright 2006-2007 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.job;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.core.step.StepSupport;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
/**
* @author Dave Syer
*
*/
public class ConditionalJobTests {
private ConditionalJob job = new ConditionalJob("job");
private JobExecution jobExecution;
@Before
public void setUp() throws Exception {
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.afterPropertiesSet();
JobRepository jobRepository = (JobRepository) factory.getObject();
job.setJobRepository(jobRepository);
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
}
@Test(expected = IllegalArgumentException.class)
public void testEmptySteps() throws Exception {
job.setStepTransitions(Collections.<StepTransition> emptySet());
job.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void testNoNextStepSpecified() throws Exception {
job.setStepTransitions(Collections.singleton(new StepTransition(new StepSupport("step"), "*", "foo")));
job.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void testNoStartStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StepSupport("step"), "FAILED", "step"),
new StepTransition(new StepSupport("step"), "*")));
job.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void testNoEndStep() throws Exception {
job.setStepTransitions(Collections.singleton(new StepTransition(new StepSupport("step"), "FAILED", "step")));
job.setStartStepName("step");
job.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void testMultipleStartSteps() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1"), "*"), new StepTransition(
new StubStep("step2"), "*")));
job.afterPropertiesSet();
}
@Test
public void testNoMatchForNextStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1"), "FOO", "step2"),
new StepTransition(new StubStep("step2"), "*")));
job.afterPropertiesSet();
try {
job.doExecute(jobExecution);
fail("Expected JobExecutionException");
}
catch (JobExecutionException e) {
// expected
String message = e.getMessage();
assertTrue("Wrong message: " + message, message.toLowerCase().contains("next step not found"));
}
}
@Test
public void testOneStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1"), "*")));
job.afterPropertiesSet();
StepExecution stepExecution = job.doExecute(jobExecution);
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testExplicitStartStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step"), "FAILED", "step"),
new StepTransition(new StubStep("step"), "*")));
job.setStartStepName("step");
job.afterPropertiesSet();
StepExecution stepExecution = job.doExecute(jobExecution);
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testTwoSteps() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1"), "*", "step2"),
new StepTransition(new StubStep("step2"), "*")));
job.afterPropertiesSet();
StepExecution stepExecution = job.doExecute(jobExecution);
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
}
@Test
public void testFailedStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException,
UnexpectedJobExecutionException {
stepExecution.setStatus(BatchStatus.FAILED);
stepExecution.setExitStatus(ExitStatus.FAILED);
}
}, "*", "step2"), new StepTransition(new StubStep("step2"), "*")));
job.afterPropertiesSet();
StepExecution stepExecution = job.doExecute(jobExecution);
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
}
@Test
public void testStoppingStep() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1") {
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException,
UnexpectedJobExecutionException {
stepExecution.setStatus(BatchStatus.STOPPED);
}
}, "*", "step2"),
new StepTransition(new StubStep("step2"), "*")));
job.afterPropertiesSet();
try {
job.doExecute(jobExecution);
fail("Expected JobInterruptedException");
} catch (JobInterruptedException e) {
// expected
}
assertEquals(1, jobExecution.getStepExecutions().size());
}
@Test
public void testBranching() throws Exception {
job.setStepTransitions(Arrays.asList(new StepTransition(new StubStep("step1"), "*", "step2"),
new StepTransition(new StubStep("step1"), "COMPLETED", "step3"), new StepTransition(new StubStep(
"step2"), "*"), new StepTransition(new StubStep("step3"), "*")));
job.afterPropertiesSet();
StepExecution stepExecution = job.doExecute(jobExecution);
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
assertEquals("step3", stepExecution.getStepName());
}
/**
* @author Dave Syer
*
*/
private static class StubStep extends StepSupport {
/**
*
*/
public StubStep() {
super();
}
/**
* @param string
*/
public StubStep(String string) {
super(string);
}
/**
* @see StepSupport#execute(StepExecution)
*/
@Override
public void execute(StepExecution stepExecution) throws JobInterruptedException,
UnexpectedJobExecutionException {
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setExitStatus(ExitStatus.FINISHED);
}
}
}

View File

@@ -110,20 +110,18 @@ public class SimpleJobTests {
job = new SimpleJob();
job.setJobRepository(jobRepository);
step1 = new StubStep("TestStep1");
step1 = new StubStep("TestStep1", jobRepository);
step1.setCallback(new Runnable() {
public void run() {
list.add("default");
}
});
step2 = new StubStep("TestStep2");
step2 = new StubStep("TestStep2", jobRepository);
step2.setCallback(new Runnable() {
public void run() {
list.add("default");
}
});
step1.setJobRepository(jobRepository);
step2.setJobRepository(jobRepository);
List<Step> steps = new ArrayList<Step>();
steps.add(step1);
@@ -250,8 +248,8 @@ public class SimpleJobTests {
final JobInterruptedException exception = new JobInterruptedException("Interrupt!");
step1.setProcessException(exception);
job.execute(jobExecution);
assertEquals(1, jobExecution.getAllFailureExceptions().size());
assertEquals(exception, jobExecution.getAllFailureExceptions().get(0));
assertEquals(2, jobExecution.getAllFailureExceptions().size());
assertEquals(exception, jobExecution.getStepExecutions().iterator().next().getFailureExceptions().get(0));
assertEquals(0, list.size());
checkRepository(BatchStatus.STOPPED, ExitStatus.FAILED);
}
@@ -418,22 +416,24 @@ public class SimpleJobTests {
@Test
public void testInterruptJob() throws Exception {
step1 = new StubStep("interruptStep") {
step1 = new StubStep("interruptStep", jobRepository) {
public void execute(StepExecution stepExecution) throws JobInterruptedException,
UnexpectedJobExecutionException {
stepExecution.getJobExecution().stop();
super.execute(stepExecution);
}
};
job.setSteps(Arrays.asList(new Step[] { step1, step2 }));
job.execute(jobExecution);
Throwable expected = jobExecution.getAllFailureExceptions().get(0);
assertTrue(expected instanceof JobInterruptedException);
assertEquals("JobExecution interrupted.", expected.getMessage());
assertEquals(1, jobExecution.getAllFailureExceptions().size());
Throwable expected = jobExecution.getAllFailureExceptions().get(0);
assertTrue("Wrong exception "+expected, expected instanceof JobInterruptedException);
assertEquals("JobExecution interrupted.", expected.getMessage());
assertNull("Second step was not executed", step2.passedInStepContext);
assertNull("Second step was not supposed to be executed", step2.passedInStepContext);
}
/*
@@ -446,7 +446,7 @@ public class SimpleJobTests {
assertEquals(jobInstance.getId(), jobExecution.getJobId());
assertEquals(status, jobExecution.getStatus());
if (exitStatus != null) {
assertEquals(jobExecution.getExitStatus().getExitCode(), exitStatus.getExitCode());
assertEquals(exitStatus.getExitCode(), jobExecution.getExitStatus().getExitCode());
}
}
@@ -469,8 +469,9 @@ public class SimpleJobTests {
/**
* @param string
*/
public StubStep(String string) {
public StubStep(String string, JobRepository jobRepository) {
super(string);
this.jobRepository = jobRepository;
}
/**
@@ -529,14 +530,5 @@ public class SimpleJobTests {
}
/**
* Public setter for {@link JobRepository}.
*
* @param jobRepository is a mandatory dependence (no default).
*/
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2006-2007 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.job;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.batch.core.step.StepSupport;
import org.springframework.batch.repeat.ExitStatus;
/**
* @author Dave Syer
*
*/
public class StepTransitionTests {
@Test
public void testIsEnd() {
StepTransition transition = new StepTransition(new StepSupport(), "");
assertTrue(transition.isEnd());
assertNull(transition.getNext());
}
@Test
public void testMatchesStar() {
StepTransition transition = new StepTransition(new StepSupport(), "*", "start");
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testMatchesNull() {
StepTransition transition = new StepTransition(new StepSupport(), null, "start");
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testMatchesEmpty() {
StepTransition transition = new StepTransition(new StepSupport(), "", "start");
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testMatchesExact() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTINUABLE", "start");
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testMatchesWildcard() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN*", "start" );
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testMatchesPlaceholder() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN???LE", "start");
assertTrue(transition.matches(ExitStatus.CONTINUABLE));
}
@Test
public void testSimpleOrderingEqual() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN???LE", "start");
assertEquals(0, transition.compareTo(transition));
}
@Test
public void testSimpleOrderingMoreGeneral() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN???LE", "start");
StepTransition other = new StepTransition(new StepSupport(), "CONTINUABLE", "start");
assertEquals(1, transition.compareTo(other));
assertEquals(-1, other.compareTo(transition));
}
@Test
public void testSimpleOrderingMostGeneral() {
StepTransition transition = new StepTransition(new StepSupport(), "*", "start");
StepTransition other = new StepTransition(new StepSupport(), "CONTINUABLE", "start");
assertEquals(1, transition.compareTo(other));
assertEquals(-1, other.compareTo(transition));
}
@Test
public void testSubstringAndWildcard() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN*", "start");
StepTransition other = new StepTransition(new StepSupport(), "CONTINUABLE", "start");
assertEquals(1, transition.compareTo(other));
assertEquals(-1, other.compareTo(transition));
}
@Test
public void testSimpleOrderingMostToNextGeneral() {
StepTransition transition = new StepTransition(new StepSupport(), "*", "start");
StepTransition other = new StepTransition(new StepSupport(), "C?", "start");
assertEquals(1, transition.compareTo(other));
assertEquals(-1, other.compareTo(transition));
}
@Test
public void testSimpleOrderingAdjacent() {
StepTransition transition = new StepTransition(new StepSupport(), "CON*", "start");
StepTransition other = new StepTransition(new StepSupport(), "CON?", "start");
assertEquals(1, transition.compareTo(other));
assertEquals(-1, other.compareTo(transition));
}
@Test
public void testToString() {
StepTransition transition = new StepTransition(new StepSupport(), "CONTIN???LE", "start");
String string = transition.toString();
assertTrue("Wrong string: " + string, string.contains("StepTransition"));
assertTrue("Wrong string: " + string, string.contains("start"));
assertTrue("Wrong string: " + string, string.contains("CONTIN???LE"));
assertTrue("Wrong string: " + string, string.contains("next="));
}
}