RESOLVED - BATCH-1032: Modify AbstractJobTests in test project to be able to launch FlowJob steps individually

applied patch with some tweaks
This commit is contained in:
robokaso
2009-01-27 17:42:45 +00:00
parent 73bfca8bb8
commit 9f9282a2a4
13 changed files with 693 additions and 583 deletions

View File

@@ -1,157 +1,164 @@
/*
* 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.flow;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.StartLimitExceededException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.AbstractJob;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.util.Assert;
/**
* @author Dave Syer
*
*/
public class FlowJob extends AbstractJob {
private Flow flow;
/**
* Create a {@link FlowJob} with null name and no flow (invalid state).
*/
public FlowJob() {
super();
}
/**
* Create a {@link FlowJob} with provided name and no flow (invalid state).
*/
public FlowJob(String name) {
super(name);
}
/**
* Public setter for the flow.
* @param flow the flow to set
*/
public void setFlow(Flow flow) {
this.flow = flow;
}
/**
* @see AbstractJob#doExecute(JobExecution)
*/
@Override
protected StepExecution doExecute(final JobExecution execution) throws JobExecutionException {
try {
FlowExecution result = flow.start(new JobFlowExecutor(execution));
return getLastStepExecution(execution, result);
}
catch (FlowExecutionException e) {
if (e.getCause() instanceof JobExecutionException) {
throw (JobExecutionException) e.getCause();
}
throw new JobExecutionException("Flow execution ended unexpectedly", e);
}
}
/**
* @param execution the current {@link JobExecution}
* @param result the result of the flow execution
* @return a {@link StepExecution} with matching properties to the result
*/
private StepExecution getLastStepExecution(JobExecution execution, FlowExecution result) {
StepExecution value = null;
StepExecution backup = null;
for (StepExecution stepExecution : execution.getStepExecutions()) {
if (stepExecution.getStepName().equals(result.getName())
&& stepExecution.getExitStatus().getExitCode().equals(result.getStatus())) {
value = stepExecution;
}
if (isLater(backup,stepExecution)) {
backup = stepExecution;
}
}
if (value==null) {
value = backup;
}
Assert.state(value != null, String.format(
"Could not locate step execution matching expected properties: flowExecution=%s, stepExecutions=%s",
result, execution.getStepExecutions()));
return value;
}
/**
* @param first
* @param second
* @return true if the first is deemed to be executed after the second
*/
private boolean isLater(StepExecution first, StepExecution second) {
if (first==null) {
return true;
}
if (first.getEndTime()==null) {
return first.getStartTime().after(second.getStartTime());
}
if (second.getEndTime()==null) {
return false;
}
return first.getEndTime().after(second.getEndTime());
}
/**
* @author Dave Syer
*
*/
private class JobFlowExecutor implements FlowExecutor {
private final ThreadLocal<StepExecution> stepExecutionHolder = new ThreadLocal<StepExecution>();
private final JobExecution execution;
/**
* @param execution
*/
private JobFlowExecutor(JobExecution execution) {
this.execution = execution;
stepExecutionHolder.set(null);
}
public String executeStep(Step step) throws JobInterruptedException, JobRestartException, StartLimitExceededException {
StepExecution stepExecution = handleStep(step, execution);
stepExecutionHolder.set(stepExecution);
return stepExecution==null ? FlowExecution.COMPLETED : stepExecution.getExitStatus().getExitCode();
}
public JobExecution getJobExecution() {
return execution;
}
public StepExecution getStepExecution() {
return stepExecutionHolder.get();
}
public void close(FlowExecution result) {
stepExecutionHolder.set(null);
}
}
}
/*
* 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.flow;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.StartLimitExceededException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.AbstractJob;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.util.Assert;
/**
* @author Dave Syer
*
*/
public class FlowJob extends AbstractJob {
private Flow flow;
/**
* Create a {@link FlowJob} with null name and no flow (invalid state).
*/
public FlowJob() {
super();
}
/**
* Create a {@link FlowJob} with provided name and no flow (invalid state).
*/
public FlowJob(String name) {
super(name);
}
/**
* Public setter for the flow.
* @param flow the flow to set
*/
public void setFlow(Flow flow) {
this.flow = flow;
}
/**
* @return the flow
*/
public Flow getFlow(){
return this.flow;
}
/**
* @see AbstractJob#doExecute(JobExecution)
*/
@Override
protected StepExecution doExecute(final JobExecution execution) throws JobExecutionException {
try {
FlowExecution result = flow.start(new JobFlowExecutor(execution));
return getLastStepExecution(execution, result);
}
catch (FlowExecutionException e) {
if (e.getCause() instanceof JobExecutionException) {
throw (JobExecutionException) e.getCause();
}
throw new JobExecutionException("Flow execution ended unexpectedly", e);
}
}
/**
* @param execution the current {@link JobExecution}
* @param result the result of the flow execution
* @return a {@link StepExecution} with matching properties to the result
*/
private StepExecution getLastStepExecution(JobExecution execution, FlowExecution result) {
StepExecution value = null;
StepExecution backup = null;
for (StepExecution stepExecution : execution.getStepExecutions()) {
if (stepExecution.getStepName().equals(result.getName())
&& stepExecution.getExitStatus().getExitCode().equals(result.getStatus())) {
value = stepExecution;
}
if (isLater(backup,stepExecution)) {
backup = stepExecution;
}
}
if (value==null) {
value = backup;
}
Assert.state(value != null, String.format(
"Could not locate step execution matching expected properties: flowExecution=%s, stepExecutions=%s",
result, execution.getStepExecutions()));
return value;
}
/**
* @param first
* @param second
* @return true if the first is deemed to be executed after the second
*/
private boolean isLater(StepExecution first, StepExecution second) {
if (first==null) {
return true;
}
if (first.getEndTime()==null) {
return first.getStartTime().after(second.getStartTime());
}
if (second.getEndTime()==null) {
return false;
}
return first.getEndTime().after(second.getEndTime());
}
/**
* @author Dave Syer
*
*/
private class JobFlowExecutor implements FlowExecutor {
private final ThreadLocal<StepExecution> stepExecutionHolder = new ThreadLocal<StepExecution>();
private final JobExecution execution;
/**
* @param execution
*/
private JobFlowExecutor(JobExecution execution) {
this.execution = execution;
stepExecutionHolder.set(null);
}
public String executeStep(Step step) throws JobInterruptedException, JobRestartException, StartLimitExceededException {
StepExecution stepExecution = handleStep(step, execution);
stepExecutionHolder.set(stepExecution);
return stepExecution==null ? FlowExecution.COMPLETED : stepExecution.getExitStatus().getExitCode();
}
public JobExecution getJobExecution() {
return execution;
}
public StepExecution getStepExecution() {
return stepExecutionHolder.get();
}
public void close(FlowExecution result) {
stepExecutionHolder.set(null);
}
}
}

View File

@@ -81,6 +81,14 @@ public class SimpleFlow implements Flow, InitializingBean {
this.stateTransitions = stateTransitions;
}
/**
* @param stateName
* @return state with given name, null if not found
*/
public State getState(String stateName) {
return stateMap.get(stateName);
}
/**
* Locate start state and pre-populate data structures needed for execution.
*

View File

@@ -1,56 +1,62 @@
/*
* 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.flow.support.state;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
/**
* {@link State} implementation that delegates to a {@link FlowExecutor} to
* execute the specified {@link Step}.
*
* @author Dave Syer
*
*/
public class StepState extends AbstractState {
private final Step step;
/**
* @param step the step that will be executed
*/
public StepState(Step step) {
super(step.getName());
this.step = step;
}
/**
* @param name for the step that will be executed
* @param step the step that will be executed
*/
public StepState(String name, Step step) {
super(name);
this.step = step;
}
@Override
public String handle(FlowExecutor executor) throws Exception {
return executor.executeStep(step);
}
}
/*
* 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.flow.support.state;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
/**
* {@link State} implementation that delegates to a {@link FlowExecutor} to
* execute the specified {@link Step}.
*
* @author Dave Syer
*
*/
public class StepState extends AbstractState {
private final Step step;
/**
* @param step the step that will be executed
*/
public StepState(Step step) {
super(step.getName());
this.step = step;
}
/**
* @param name for the step that will be executed
* @param step the step that will be executed
*/
public StepState(String name, Step step) {
super(name);
this.step = step;
}
@Override
public String handle(FlowExecutor executor) throws Exception {
return executor.executeStep(step);
}
/**
* @return the step
*/
public Step getStep() {
return step;
}
}

View File

@@ -9,8 +9,10 @@
<configs>
<config>src/test/resources/data-source-context.xml</config>
<config>src/test/resources/simple-job-launcher-context.xml</config>
<config>src/test/resources/jobs/sampleJob.xml</config>
<config>src/test/resources/org/springframework/batch/sample/config/common-context.xml</config>
<config>src/test/resources/jobs/sampleFlowJob.xml</config>
<config>src/test/resources/jobs/sampleSimpleJob.xml</config>
<config>src/test/resources/jobs/sample-steps.xml</config>
</configs>
<configSets>
<configSet>
@@ -19,7 +21,6 @@
<incomplete>false</incomplete>
<configs>
<config>src/test/resources/data-source-context.xml</config>
<config>src/test/resources/jobs/sampleJob.xml</config>
<config>src/test/resources/org/springframework/batch/sample/config/common-context.xml</config>
<config>src/test/resources/simple-job-launcher-context.xml</config>
</configs>

View File

@@ -1,111 +1,224 @@
/*
* 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.test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Base class for testing batch jobs using the SimpleJob implementation. It
* provides methods for launching a Job, or individual Steps within a Job on
* their own, allowing for end to end testing of individual steps, without
* having to run every step in the job. Any test classes inheriting from this
* class should make sure they are part of an ApplicationContext, which is
* generally expected to be done as part of the Spring test framework.
* Furthermore, the ApplicationContext in which it is a part of is expected to
* have one {@link JobLauncher}, {@link JobRepository}, and a single Job
* implementation. It should be noted that using any of the methods that don't
* conain {@link JobParameters} in their signature, will result in one being
* created with the current system time as a parameter.
*
* @author Lucas Ward
* @author Dan Garrette
* @since 2.0
*/
public abstract class AbstractJobTests {
/** Logger */
protected final Log logger = LogFactory.getLog(getClass());
@Autowired
private JobLauncher launcher;
@Autowired
private Job job;
@Autowired
private JobRepository jobRepository;
public JobRepository getJobRepository() {
return jobRepository;
}
public Job getJob() {
return job;
}
/**
* Public getter for the launcher.
*
* @return the launcher
*/
protected JobLauncher getJobLauncher() {
return launcher;
}
/**
* Launch the entire job, including all steps, in order.
*
* @return JobExecution, so that the test may validate the exit status
* @throws Exception
*/
public JobExecution launchJob() throws Exception {
return this.launchJob(this.makeUniqueJobParameters());
}
/**
* Launch the entire job, including all steps, in order.
*
* @param jobParameters
* @return JobExecution, so that the test may validate the exit status
* @throws Exception
*/
public JobExecution launchJob(JobParameters jobParameters) throws Exception {
return getJobLauncher().run(this.job, jobParameters);
}
/**
* @return a new JobParameters object containing only a parameter for the
* current timestamp, to ensure that the job instance will be unique
*/
private JobParameters makeUniqueJobParameters() {
Map<String, JobParameter> parameters = new HashMap<String, JobParameter>();
parameters.put("timestamp", new JobParameter(new Date().getTime()));
return new JobParameters(parameters);
}
}
/*
* 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.test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.SimpleJob;
import org.springframework.batch.core.job.flow.FlowJob;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.batch.core.job.flow.support.State;
import org.springframework.batch.core.job.flow.support.state.StepState;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
/**
* <p>
* Base class for testing batch jobs. It provides methods for launching an
* entire {@link Job}, allowing for end to end testing of individual steps,
* without having to run every step in the job. Any test classes inheriting from
* this class should make sure they are part of an {@link ApplicationContext},
* which is generally expected to be done as part of the Spring test framework.
* Furthermore, the {@link ApplicationContext} in which it is a part of is
* expected to have one {@link JobLauncher}, {@link JobRepository}, and a
* single {@link Job} implementation.
*
* <p>
* This class also provides the ability to run {@link Step}s from a
* {@link FlowJob} or {@link SimpleJob} individually. By launching {@link Step}s
* within a {@link Job} on their own, end to end testing of individual steps can
* be performed without having to run every step in the job.
*
* <p>
* It should be noted that using any of the methods that don't contain
* {@link JobParameters} in their signature, will result in one being created
* with the current system time as a parameter. This will ensure restartability
* when no parameters are provided.
*
* @author Lucas Ward
* @author Dan Garrette
* @since 2.0
*/
public abstract class AbstractJobTests {
/** Logger */
protected final Log logger = LogFactory.getLog(getClass());
@Autowired
private JobLauncher launcher;
@Autowired
private Job job;
@Autowired
private JobRepository jobRepository;
private StepRunner stepRunner;
private Map<String, Step> stepMap;
/**
* @return the job repository
*/
public JobRepository getJobRepository() {
return jobRepository;
}
/**
* @return the job
*/
public Job getJob() {
return job;
}
/**
* @return the launcher
*/
protected JobLauncher getJobLauncher() {
return launcher;
}
/**
* Launch the entire job, including all steps.
*
* @return JobExecution, so that the test may validate the exit status
* @throws Exception
*/
public JobExecution launchJob() throws Exception {
return this.launchJob(this.makeUniqueJobParameters());
}
/**
* Launch the entire job, including all steps
*
* @param jobParameters
* @return JobExecution, so that the test may validate the exit status
* @throws Exception
*/
public JobExecution launchJob(JobParameters jobParameters) throws Exception {
return getJobLauncher().run(this.job, jobParameters);
}
/**
* @return a new JobParameters object containing only a parameter for the
* current timestamp, to ensure that the job instance will be unique
*/
private JobParameters makeUniqueJobParameters() {
Map<String, JobParameter> parameters = new HashMap<String, JobParameter>();
parameters.put("timestamp", new JobParameter(new Date().getTime()));
return new JobParameters(parameters);
}
protected StepRunner getStepRunner() {
if (this.stepRunner == null) {
this.stepRunner = new StepRunner(getJobLauncher(), getJobRepository());
}
return this.stepRunner;
}
/**
* Launch just the specified step in the job.
*
* @param stepName
*/
public JobExecution launchStep(String stepName) {
return getStepRunner().launchStep(getStep(stepName));
}
/**
* @param stepName
* @return
*/
public Step getStep(String stepName) {
Job job = getJob();
if (job instanceof FlowJob) {
return getFlowJobStep(stepName);
}
else if (job instanceof SimpleJob) {
return getSimpleJobStep(stepName);
}
else {
throw new IllegalStateException("Job is neither a FlowJob or a SimpleJob");
}
}
/**
* Extract the step from a FlowJob. Throw an exception of the step does not
* exist.
*
* @param stepName
* @return the step
*/
private Step getFlowJobStep(String stepName) {
try{
State state = ((SimpleFlow) ((FlowJob) getJob()).getFlow()).getState(stepName);
Assert.notNull(state, "no matching state found in flow for " + stepName);
Assert.isInstanceOf(StepState.class, state);
return ((StepState) state).getStep();
}
catch(IllegalArgumentException e)
{
throw new IllegalStateException("No Step found with name: [" + stepName + "]");
}
}
/**
* Extract the step from a SimpleJob. Throw an exception of the step does
* not exist.
*
* @param stepName
* @return the step
*/
private Step getSimpleJobStep(String stepName) {
if (this.stepMap == null) {
//
// Populate the step map
//
SimpleJob simpleJob = (SimpleJob) getJob();
this.stepMap = new HashMap<String, Step>();
for (Step step : simpleJob.getSteps()) {
this.stepMap.put(step.getName(), step);
}
}
if (!this.stepMap.containsKey(stepName)) {
throw new IllegalStateException("No Step found with name: [" + stepName + "]");
}
return this.stepMap.get(stepName);
}
/**
* Launch just the specified step in the job.
*
* @param stepName
* @param jobParameters
*/
public JobExecution launchStep(String stepName, JobParameters jobParameters) {
return getStepRunner().launchStep(getStep(stepName), jobParameters);
}
}

View File

@@ -1,101 +0,0 @@
/*
* 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.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.SimpleJob;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
/**
* Base class for testing batch jobs using the SimpleJob implementation.
* It provides methods for launching a Job, or individual Steps within a Job on their own,
* allowing for end to end testing of individual steps, without having to run every step
* in the job. Any test classes inheriting from this class should make sure they are part
* of an ApplicationContext, which is generally expected to be done as part of the Spring
* test framework. Furthermore, the ApplicationContext in which it is a part of is expected
* to have one {@link JobLauncher}, {@link JobRepository}, and a single Job implementation.
* It should be noted that using any of the methods that don't conain {@link JobParameters}
* in their signature, will result in one being created with the current system time as a
* parameter.
*
* @author Lucas Ward
* @author Dan Garrette
* @since 2.0
*/
public abstract class AbstractSimpleJobTests extends AbstractJobTests {
private StepRunner stepRunner;
private Map<String, Step> stepMap = new HashMap<String, Step>();
private List<Step> stepList = new ArrayList<Step>();
@Before
public void setUpSteps() {
for (Step step : (getSimpleJob()).getSteps()) {
stepMap.put(step.getName(), step);
stepList.add(step);
}
}
protected StepRunner getStepRunner() {
if(stepRunner == null){
stepRunner = new StepRunner(getJobLauncher(), getJobRepository());
}
return stepRunner;
}
public SimpleJob getSimpleJob() {
return (SimpleJob)getJob();
}
public Step getStep(String stepName){
if(!stepMap.containsKey(stepName)){
throw new IllegalStateException("No Step found with name: [" + stepName + "]");
}
return stepMap.get(stepName);
}
/**
* Launch just the specified step in the job.
*
* @param stepName
*/
public JobExecution launchStep(String stepName) {
return getStepRunner().launchStep(getStep(stepName));
}
/**
* Launch just the specified step in the job.
*
* @param stepName
* @param jobParameters
*/
public JobExecution launchStep(String stepName, JobParameters jobParameters) {
return getStepRunner().launchStep(getStep(stepName), jobParameters);
}
}

View File

@@ -1,64 +1,66 @@
package org.springframework.batch.test;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/jobs/sampleJob.xml" })
public class SampleJobTests extends AbstractSimpleJobTests {
private SimpleJdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(SimpleJdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Before
public void setUp() {
this.jdbcTemplate.update("create table TESTS (ID integer, NAME varchar(40))");
}
@After
public void tearDown() {
this.jdbcTemplate.update("drop table TESTS");
}
@Test
public void testJob() throws Exception {
assertEquals(BatchStatus.COMPLETED,this.launchJob().getStatus());
this.verifyTasklet(1);
this.verifyTasklet(2);
}
@Test(expected=IllegalStateException.class)
public void voidTestNonExistentStep(){
launchStep("nonExistent");
}
@Test
public void testStep1Execution() {
assertEquals(BatchStatus.COMPLETED, this.launchStep("step1").getStatus());
this.verifyTasklet(1);
}
@Test
public void testStep2Execution() {
assertEquals(BatchStatus.COMPLETED, this.launchStep("step2").getStatus());
this.verifyTasklet(2);
}
private void verifyTasklet(int id) {
assertEquals(id, jdbcTemplate.queryForInt("SELECT ID from TESTS where NAME = 'SampleTasklet" + id + "'"));
}
}
package org.springframework.batch.test;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
/**
* This is an abstract test class to be used by test classes to test the
* {@link AbstractJobTests} class.
*
* @author Dan Garrette
* @since 2.0
*/
public abstract class AbstractSampleJobTests extends AbstractJobTests {
private SimpleJdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(SimpleJdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Before
public void setUp() {
this.jdbcTemplate.update("create table TESTS (ID integer, NAME varchar(40))");
}
@After
public void tearDown() {
this.jdbcTemplate.update("drop table TESTS");
}
@Test
public void testJob() throws Exception {
assertEquals(BatchStatus.COMPLETED, this.launchJob().getStatus());
this.verifyTasklet(1);
this.verifyTasklet(2);
}
@Test(expected = IllegalStateException.class)
public void testNonExistentStep() {
launchStep("nonExistent");
}
@Test
public void testStep1Execution() {
assertEquals(BatchStatus.COMPLETED, this.launchStep("step1").getStatus());
this.verifyTasklet(1);
}
@Test
public void testStep2Execution() {
assertEquals(BatchStatus.COMPLETED, this.launchStep("step2").getStatus());
this.verifyTasklet(2);
}
private void verifyTasklet(int id) {
assertEquals(id, jdbcTemplate.queryForInt("SELECT ID from TESTS where NAME = 'SampleTasklet" + id + "'"));
}
}

View File

@@ -0,0 +1,19 @@
package org.springframework.batch.test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.job.flow.FlowJob;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This class will specifically test the capabilities of
* {@link AbstractSampleJobTests} to test {@link FlowJob}s.
*
* @author Dan Garrette
* @since 2.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/jobs/sampleFlowJob.xml" })
public class SampleFlowJobTests extends AbstractSampleJobTests {
}

View File

@@ -0,0 +1,19 @@
package org.springframework.batch.test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.job.SimpleJob;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This class will specifically test the capabilities of
* {@link AbstractSampleJobTests} to test {@link SimpleJob}s.
*
* @author Dan Garrette
* @since 2.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/jobs/sampleSimpleJob.xml" })
public class SampleSimpleJobTests extends AbstractSampleJobTests {
}

View File

@@ -1,60 +1,60 @@
package org.springframework.batch.test;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/jobs/sampleJob.xml" })
public class SampleStepTests implements ApplicationContextAware{
@Autowired
private SimpleJdbcTemplate jdbcTemplate;
private StepRunner stepRunner;
private ApplicationContext context;
@Autowired
private JobLauncher jobLauncher;
@Autowired
private JobRepository jobRepository;
@Before
public void setUp() {
jdbcTemplate.update("create table TESTS (ID integer, NAME varchar(40))");
stepRunner = new StepRunner(jobLauncher, jobRepository);
}
@After
public void tearDown() {
this.jdbcTemplate.update("drop table TESTS");
}
@Test
public void testTasklet() {
Step step = (Step)context.getBean("step2");
assertEquals(BatchStatus.COMPLETED, stepRunner.launchStep(step).getStatus());
assertEquals(2, jdbcTemplate.queryForInt("SELECT ID from TESTS where NAME = 'SampleTasklet2'"));
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
}
package org.springframework.batch.test;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/jobs/sample-steps.xml" })
public class SampleStepTests implements ApplicationContextAware{
@Autowired
private SimpleJdbcTemplate jdbcTemplate;
private StepRunner stepRunner;
private ApplicationContext context;
@Autowired
private JobLauncher jobLauncher;
@Autowired
private JobRepository jobRepository;
@Before
public void setUp() {
jdbcTemplate.update("create table TESTS (ID integer, NAME varchar(40))");
stepRunner = new StepRunner(jobLauncher, jobRepository);
}
@After
public void tearDown() {
this.jdbcTemplate.update("drop table TESTS");
}
@Test
public void testTasklet() {
Step step = (Step)context.getBean("step2");
assertEquals(BatchStatus.COMPLETED, stepRunner.launchStep(step).getStatus());
assertEquals(2, jdbcTemplate.queryForInt("SELECT ID from TESTS where NAME = 'SampleTasklet2'"));
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
}

View File

@@ -1,33 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="sampleJob" parent="simpleJob">
<property name="steps">
<list>
<bean id="step1" parent="taskletStep">
<property name="tasklet">
<bean class="org.springframework.batch.test.sample.SampleTasklet">
<constructor-arg value="1" />
</bean>
</property>
</bean>
<ref bean="step2" />
</list>
</property>
</bean>
<bean id="step2" parent="taskletStep">
<property name="tasklet">
<bean class="org.springframework.batch.test.sample.SampleTasklet">
<constructor-arg value="2" />
</bean>
</property>
</bean>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="step1" parent="taskletStep">
<property name="tasklet">
<bean class="org.springframework.batch.test.sample.SampleTasklet">
<constructor-arg value="1" />
</bean>
</property>
</bean>
<bean id="step2" parent="taskletStep">
<property name="tasklet">
<bean class="org.springframework.batch.test.sample.SampleTasklet">
<constructor-arg value="2" />
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<beans:import resource="sample-steps.xml" />
<job id="sampleFlowJob">
<step name="step1" next="step2"/>
<step name="step2"/>
</job>
</beans:beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<import resource="sample-steps.xml" />
<bean id="sampleJob" parent="simpleJob">
<property name="steps">
<list>
<ref bean="step1" />
<ref bean="step2" />
</list>
</property>
</bean>
</beans>