[BATCH-429] Moved all code out of execution

This commit is contained in:
nebhale
2008-03-07 16:02:22 +00:00
parent 5a04a9ddcd
commit bfb9447d6b
153 changed files with 188 additions and 187 deletions

View File

@@ -0,0 +1,37 @@
/*
* 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.execution;
import junit.framework.TestCase;
public abstract class AbstractExceptionTests extends TestCase {
public void testExceptionString() throws Exception {
Exception exception = getException("foo");
assertEquals("foo", exception.getMessage());
}
public void testExceptionStringThrowable() throws Exception {
Exception exception = getException("foo", new IllegalStateException());
assertEquals("foo", exception.getMessage().substring(0, 3));
}
public abstract Exception getException(String msg) throws Exception;
public abstract Exception getException(String msg, Throwable t) throws Exception;
}

View File

@@ -0,0 +1,131 @@
/*
* 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.execution.configuration;
import java.util.Collection;
import junit.framework.TestCase;
import org.springframework.batch.core.repository.DuplicateJobException;
import org.springframework.batch.core.repository.NoSuchJobException;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.beans.FatalBeanException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Dave Syer
*
*/
public class JobRegistryBeanPostProcessorTests extends TestCase {
private JobRegistryBeanPostProcessor processor = new JobRegistryBeanPostProcessor();
public void testInitialization() throws Exception {
try {
processor.afterPropertiesSet();
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
assertTrue(e.getMessage().indexOf("JobConfigurationRegistry") >= 0);
}
}
public void testBeforeInitialization() throws Exception {
// should be a no-op
assertEquals("foo", processor.postProcessAfterInitialization("foo",
"bar"));
}
public void testAfterInitializationWithWrongType() throws Exception {
// should be a no-op
assertEquals("foo", processor.postProcessAfterInitialization("foo",
"bar"));
}
public void testAfterInitializationWithCorrectType() throws Exception {
MapJobRegistry registry = new MapJobRegistry();
processor.setJobRegistry(registry);
JobSupport configuration = new JobSupport();
configuration.setBeanName("foo");
assertEquals(configuration, processor.postProcessAfterInitialization(
configuration, "bar"));
assertEquals(configuration, registry.getJob("foo"));
}
public void testAfterInitializationWithDuplicate() throws Exception {
MapJobRegistry registry = new MapJobRegistry();
processor.setJobRegistry(registry);
JobSupport configuration = new JobSupport();
configuration.setBeanName("foo");
processor.postProcessAfterInitialization(configuration, "bar");
try {
processor.postProcessAfterInitialization(configuration, "spam");
fail("Expected FatalBeanException");
} catch (FatalBeanException e) {
// Expected
assertTrue(e.getCause() instanceof DuplicateJobException);
}
}
public void testUnregisterOnDestroy() throws Exception {
MapJobRegistry registry = new MapJobRegistry();
processor.setJobRegistry(registry);
JobSupport configuration = new JobSupport();
configuration.setBeanName("foo");
assertEquals(configuration, processor.postProcessAfterInitialization(
configuration, "bar"));
processor.destroy();
try {
assertEquals(null, registry.getJob("foo"));
fail("Expected NoSuchJobConfigurationException");
} catch (NoSuchJobException e) {
// expected
}
}
public void testExecutionWithApplicationContext() throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"test-context.xml", getClass());
MapJobRegistry registry = (MapJobRegistry) context
.getBean("registry");
Collection configurations = registry.getJobNames();
// System.err.println(configurations);
String[] names = context.getBeanNamesForType(JobSupport.class);
int count = names.length;
// Each concrete bean of type JobConfiguration is registered...
assertEquals(count, configurations.size());
// N.B. there is a failure / wonky mode where a parent bean is given an
// explicit name or beanName (using property setter): in this case then
// child beans will have the same name and will be re-registered (and
// override, if the registry supports that).
assertNotNull(registry.getJob("test-job"));
assertEquals(context.getBean("test-job-with-name"), registry
.getJob("foo"));
assertEquals(context.getBean("test-job-with-bean-name"), registry
.getJob("bar"));
assertEquals(context.getBean("test-job-with-parent-and-name"), registry
.getJob("spam"));
assertEquals(context.getBean("test-job-with-parent-and-bean-name"),
registry.getJob("bucket"));
assertEquals(context.getBean("test-job-with-concrete-parent"), registry
.getJob("maps"));
assertEquals(context.getBean("test-job-with-concrete-parent-and-name"),
registry.getJob("oof"));
assertEquals(context
.getBean("test-job-with-concrete-parent-and-bean-name"),
registry.getJob("rab"));
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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.execution.configuration;
import java.util.Collection;
import junit.framework.TestCase;
import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.repository.DuplicateJobException;
import org.springframework.batch.core.repository.NoSuchJobException;
import org.springframework.batch.execution.job.JobSupport;
/**
* @author Dave Syer
*
*/
public class MapJobRegistryTests extends TestCase {
private MapJobRegistry registry = new MapJobRegistry();
/**
* Test method for {@link org.springframework.batch.execution.configuration.MapJobRegistry#unregister(String)}.
* @throws Exception
*/
public void testUnregister() throws Exception {
registry.register(new ReferenceJobFactory(new JobSupport("foo")));
assertNotNull(registry.getJob("foo"));
registry.unregister("foo");
try {
assertNull(registry.getJob("foo"));
fail("Expected NoSuchJobConfigurationException");
}
catch (NoSuchJobException e) {
// expected
assertTrue(e.getMessage().indexOf("foo")>=0);
}
}
/**
* Test method for {@link org.springframework.batch.execution.configuration.MapJobRegistry#getJob(java.lang.String)}.
*/
public void testReplaceDuplicateConfiguration() throws Exception {
registry.register(new ReferenceJobFactory(new JobSupport("foo")));
try {
registry.register(new ReferenceJobFactory(new JobSupport("foo")));
fail("Expected DuplicateJobConfigurationException");
} catch (DuplicateJobException e) {
// unexpected: even if the job is different we want a DuplicateJobException
assertTrue(e.getMessage().indexOf("foo")>=0);
}
}
/**
* Test method for {@link org.springframework.batch.execution.configuration.MapJobRegistry#getJob(java.lang.String)}.
*/
public void testRealDuplicateConfiguration() throws Exception {
JobFactory jobFactory = new ReferenceJobFactory(new JobSupport("foo"));
registry.register(jobFactory);
try {
registry.register(jobFactory);
fail("Unexpected DuplicateJobConfigurationException");
} catch (DuplicateJobException e) {
// expected
assertTrue(e.getMessage().indexOf("foo")>=0);
}
}
/**
* Test method for {@link org.springframework.batch.execution.configuration.MapJobRegistry#getJobNames()}.
* @throws Exception
*/
public void testGetJobConfigurations() throws Exception {
JobFactory jobFactory = new ReferenceJobFactory(new JobSupport("foo"));
registry.register(jobFactory);
registry.register(new ReferenceJobFactory(new JobSupport("bar")));
Collection configurations = registry.getJobNames();
assertEquals(2, configurations.size());
assertTrue(configurations.contains(jobFactory.getJobName()));
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.execution.job;
import java.util.Collections;
import org.springframework.batch.execution.step.StepSupport;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class AbstractJobTests extends TestCase {
JobSupport job = new JobSupport("job");
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#JobConfiguration()}.
*/
public void testJobConfiguration() {
job = new JobSupport();
assertNull(job.getName());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#setBeanName(java.lang.String)}.
*/
public void testSetBeanName() {
job.setBeanName("foo");
assertEquals("job", job.getName());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#setBeanName(java.lang.String)}.
*/
public void testSetBeanNameWithNullName() {
job = new JobSupport(null);
assertEquals(null, job.getName());
job.setBeanName("foo");
assertEquals("foo", job.getName());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#setStepNames(java.util.List)}.
*/
public void testSetSteps() {
job.setSteps(Collections.singletonList(new StepSupport("step")));
assertEquals(1, job.getSteps().size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#addStepName(org.springframework.batch.core.configuration.StepConfiguration)}.
*/
public void testAddStep() {
job.addStep(new StepSupport("step"));
assertEquals(1, job.getSteps().size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#setStartLimit(int)}.
*/
public void testSetStartLimit() {
assertEquals(Integer.MAX_VALUE, job.getStartLimit());
job.setStartLimit(10);
assertEquals(10, job.getStartLimit());
}
/**
* Test method for
* {@link org.springframework.batch.execution.job.AbstractJob#setRestartable(boolean)}.
*/
public void testSetRestartable() {
assertFalse(job.isRestartable());
job.setRestartable(true);
assertTrue(job.isRestartable());
}
public void testToString() throws Exception {
String value = job.toString();
assertTrue("Should contain name: "+value, value.indexOf("name=")>=0);
}
public void testRunNotSupported() throws Exception {
try {
job.execute(null);
} catch (UnsupportedOperationException e) {
// expected
String message = e.getMessage();
assertTrue("Message should contain JobSupport: "+message, message.contains("JobSupport"));
}
}
}

View File

@@ -0,0 +1,146 @@
/*
* 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.execution.job;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.Step;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.util.ClassUtils;
/**
* Batch domain object representing a job. Job is an explicit abstraction
* representing the configuration of a job specified by a developer. It should
* be noted that restart policy is applied to the job as a whole and not to a
* step.
*
* @author Lucas Ward
* @author Dave Syer
*/
public class JobSupport implements BeanNameAware, Job {
private List steps = new ArrayList();
private String name;
private boolean restartable = false;
private int startLimit = Integer.MAX_VALUE;
/**
* Default constructor.
*/
public JobSupport() {
super();
}
/**
* Convenience constructor to immediately add name (which is mandatory but
* not final).
*
* @param name
*/
public JobSupport(String name) {
super();
this.name = name;
}
/**
* Set the name property if it is not already set. Because of the order of
* the callbacks in a Spring container the name property will be set first
* if it is present. Care is needed with bean definition inheritance - if a
* parent bean has a name, then its children need an explicit name as well,
* otherwise they will not be unique.
*
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
*/
public void setBeanName(String name) {
if (this.name == null) {
this.name = name;
}
}
/**
* Set the name property. Always overrides the default value if this object
* is a Spring bean.
*
* @see #setBeanName(java.lang.String)
*/
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.IJob#getName()
*/
public String getName() {
return name;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.IJob#getSteps()
*/
public List getSteps() {
return steps;
}
public void setSteps(List steps) {
this.steps.clear();
this.steps.addAll(steps);
}
public void addStep(Step step) {
this.steps.add(step);
}
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.IJob#getStartLimit()
*/
public int getStartLimit() {
return startLimit;
}
public void setStartLimit(int startLimit) {
this.startLimit = startLimit;
}
public void setRestartable(boolean restartable) {
this.restartable = restartable;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.IJob#isRestartable()
*/
public boolean isRestartable() {
return restartable;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.Job#run(org.springframework.batch.core.domain.JobExecution)
*/
public void execute(JobExecution execution) throws UnexpectedJobExecutionException {
throw new UnsupportedOperationException("JobSupport does not provide an implementation of run(). Use a smarter subclass.");
}
public String toString() {
return ClassUtils.getShortName(getClass()) + ": [name=" + name + "]";
}
}

View File

@@ -0,0 +1,426 @@
/*
* 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.execution.job;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.ItemSkipPolicy;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
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.listener.JobListenerSupport;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.JobExecutionDao;
import org.springframework.batch.execution.repository.dao.JobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.repository.dao.StepExecutionDao;
import org.springframework.batch.execution.step.AbstractStep;
import org.springframework.batch.execution.step.support.NeverSkipItemSkipPolicy;
import org.springframework.batch.item.AbstractItemReader;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.exception.ExceptionHandler;
import org.springframework.batch.retry.RetryPolicy;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Tests for DefaultJobLifecycle. MapJobDao and MapStepExecutionDao are used instead of a mock repository to test that
* status is being stored correctly.
*
* @author Lucas Ward
*/
public class SimpleJobTests extends TestCase {
private JobRepository jobRepository;
private JobInstanceDao jobInstanceDao;
private JobExecutionDao jobExecutionDao;
private StepExecutionDao stepExecutionDao;
private List list = new ArrayList();
private JobInstance jobInstance;
private JobExecution jobExecution;
private StepExecution stepExecution1;
private StepExecution stepExecution2;
private StubStep stepConfiguration1;
private StubStep stepConfiguration2;
private JobParameters jobParameters = new JobParameters();
private SimpleJob job;
private Step step1;
private Step step2;
protected void setUp() throws Exception {
super.setUp();
MapJobInstanceDao.clear();
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
jobInstanceDao = new MapJobInstanceDao();
jobExecutionDao = new MapJobExecutionDao();
stepExecutionDao = new MapStepExecutionDao();
jobRepository = new SimpleJobRepository(jobInstanceDao, jobExecutionDao, stepExecutionDao);
job = new SimpleJob();
job.setJobRepository(jobRepository);
stepConfiguration1 = new StubStep("TestStep1");
stepConfiguration1.setCallback(new Runnable() {
public void run() {
list.add("default");
}
});
stepConfiguration2 = new StubStep("TestStep2");
stepConfiguration2.setCallback(new Runnable() {
public void run() {
list.add("default");
}
});
stepConfiguration1.setJobRepository(jobRepository);
stepConfiguration2.setJobRepository(jobRepository);
List stepConfigurations = new ArrayList();
stepConfigurations.add(stepConfiguration1);
stepConfigurations.add(stepConfiguration2);
job.setName("testJob");
job.setSteps(stepConfigurations);
jobExecution = jobRepository.createJobExecution(job, jobParameters);
jobInstance = jobExecution.getJobInstance();
List steps = jobInstance.getJob().getSteps();
step1 = (Step) steps.get(0);
step2 = (Step) steps.get(1);
stepExecution1 = new StepExecution(step1, jobExecution, null);
stepExecution2 = new StepExecution(step2, jobExecution, null);
}
// Test to ensure the exit status returned by the last step is returned
public void testExitStatusReturned() throws JobExecutionException {
final ExitStatus customStatus = new ExitStatus(true, "test");
Step testStep = new Step() {
public void execute(StepExecution stepExecution) throws JobInterruptedException {
stepExecution.setExitStatus(customStatus);
}
public String getName() {
return "test";
}
public int getStartLimit() {
return 1;
}
public boolean isAllowStartIfComplete() {
return false;
}
};
List steps = new ArrayList();
steps.add(testStep);
job.setSteps(steps);
job.execute(jobExecution);
assertEquals(customStatus, jobExecution.getExitStatus());
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testRunNormally() throws Exception {
stepConfiguration1.setStartLimit(5);
stepConfiguration2.setStartLimit(5);
job.execute(jobExecution);
assertEquals(2, list.size());
checkRepository(BatchStatus.COMPLETED);
assertNotNull(jobExecution.getEndTime());
assertNotNull(jobExecution.getStartTime());
}
public void testRunNormallyWithListener() throws Exception {
job.setJobListeners(new JobListenerSupport[] { new JobListenerSupport() {
public void beforeJob(JobExecution jobExecution) {
list.add("before");
}
public void afterJob(JobExecution jobExecution) {
list.add("after");
}
} });
job.execute(jobExecution);
assertEquals(4, list.size());
}
public void testRunWithSimpleStepExecutor() throws Exception {
job.setJobRepository(jobRepository);
// do not set StepExecutorFactory...
stepConfiguration1.setStartLimit(5);
stepConfiguration1.setItemReader(new AbstractItemReader() {
public Object read() throws Exception {
list.add("1");
return null;
}
});
stepConfiguration2.setStartLimit(5);
stepConfiguration2.setItemReader(new AbstractItemReader() {
public Object read() throws Exception {
list.add("2");
return null;
}
});
job.execute(jobExecution);
assertEquals(2, list.size());
checkRepository(BatchStatus.COMPLETED, ExitStatus.FINISHED);
}
public void testExecutionContextIsSet() throws Exception {
testRunNormally();
assertEquals(jobInstance, jobExecution.getJobInstance());
assertEquals(2, jobExecution.getStepExecutions().size());
assertEquals(step1.getName(), stepExecution1.getStepName());
assertEquals(step2.getName(), stepExecution2.getStepName());
}
public void testInterrupted() throws Exception {
stepConfiguration1.setStartLimit(5);
stepConfiguration2.setStartLimit(5);
final JobInterruptedException exception = new JobInterruptedException("Interrupt!");
stepConfiguration1.setProcessException(exception);
try {
job.execute(jobExecution);
} catch (UnexpectedJobExecutionException e) {
assertEquals(exception, e.getCause());
}
assertEquals(0, list.size());
checkRepository(BatchStatus.STOPPED, ExitStatus.INTERRUPTED);
}
public void testFailed() throws Exception {
stepConfiguration1.setStartLimit(5);
stepConfiguration2.setStartLimit(5);
final RuntimeException exception = new RuntimeException("Foo!");
stepConfiguration1.setProcessException(exception);
try {
job.execute(jobExecution);
} catch (RuntimeException e) {
assertEquals(exception, e);
}
assertEquals(0, list.size());
checkRepository(BatchStatus.FAILED, ExitStatus.FAILED);
}
public void testStepShouldNotStart() throws Exception {
// Start policy will return false, keeping the step from being started.
stepConfiguration1.setStartLimit(0);
try {
job.execute(jobExecution);
fail("Expected BatchCriticalException");
} catch (UnexpectedJobExecutionException ex) {
// expected
assertTrue("Wrong message in exception: " + ex.getMessage(), ex.getMessage()
.indexOf("start limit exceeded") >= 0);
}
}
public void testNoSteps() throws Exception {
job.setSteps(new ArrayList());
job.execute(jobExecution);
ExitStatus exitStatus = jobExecution.getExitStatus();
assertTrue("Wrong message in execution: " + exitStatus, exitStatus.getExitDescription().indexOf(
"No steps configured") >= 0);
}
// public void testNoStepsExecuted() throws Exception {
// StepExecution completedExecution = new StepExecution("completedExecution", jobExecution);
// completedExecution.setStatus(BatchStatus.COMPLETED);
//
// job.execute(jobExecution);
// ExitStatus exitStatus = jobExecution.getExitStatus();
// assertEquals(ExitStatus.NOOP.getExitCode(), exitStatus.getExitCode());
// assertTrue("Wrong message in execution: " + exitStatus, exitStatus.getExitDescription().contains(
// "steps already completed"));
// }
public void testNotExecutedIfAlreadyStopped() throws Exception {
jobExecution.stop();
try {
job.execute(jobExecution);
} catch (UnexpectedJobExecutionException e) {
assertTrue(e.getCause() instanceof JobInterruptedException);
}
assertEquals(0, list.size());
checkRepository(BatchStatus.STOPPED, ExitStatus.NOOP);
ExitStatus exitStatus = jobExecution.getExitStatus();
assertEquals(ExitStatus.NOOP.getExitCode(), exitStatus.getExitCode());
}
/*
* Check JobRepository to ensure status is being saved.
*/
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
assertEquals(jobInstance, jobInstanceDao.getJobInstance(jobInstance.getJob(), jobParameters));
// because map dao stores in memory, it can be checked directly
JobExecution jobExecution = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), jobExecution.getJobId());
assertEquals(status, jobExecution.getStatus());
if (exitStatus != null) {
assertEquals(jobExecution.getExitStatus().getExitCode(), exitStatus.getExitCode());
}
}
private void checkRepository(BatchStatus status) {
checkRepository(status, null);
}
private class StubStep extends AbstractStep {
private Runnable runnable;
private Exception exception;
protected ExceptionHandler exceptionHandler;
protected RetryPolicy retryPolicy;
protected JobRepository jobRepository;
protected PlatformTransactionManager transactionManager;
protected ItemReader itemReader;
protected ItemWriter itemWriter;
protected ItemSkipPolicy itemSkipPolicy = new NeverSkipItemSkipPolicy();
/**
* @param string
*/
public StubStep(String string) {
super(string);
}
/**
* @param exception
*/
public void setProcessException(Exception exception) {
this.exception = exception;
}
/**
* @param runnable
*/
public void setCallback(Runnable runnable) {
this.runnable = runnable;
}
public void execute(StepExecution stepExecution) throws JobInterruptedException, UnexpectedJobExecutionException {
if (exception instanceof RuntimeException) {
stepExecution.setExitStatus(ExitStatus.FAILED);
throw (RuntimeException) exception;
}
if (exception instanceof JobInterruptedException) {
stepExecution.setExitStatus(ExitStatus.INTERRUPTED);
throw (JobInterruptedException) exception;
}
if (runnable != null) {
runnable.run();
}
stepExecution.setExitStatus(ExitStatus.FINISHED);
}
/**
* Set the name property. Always overrides the default value if this object is a Spring bean.
*
* @see #setBeanName(java.lang.String)
*/
public void setName(String name) {
this.name = name;
}
/**
* Public setter for the {@link RetryPolicy}.
*
* @param retryPolicy the {@link RetryPolicy} to set
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
public void setExceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
/**
* Public setter for {@link JobRepository}.
*
* @param jobRepository is a mandatory dependence (no default).
*/
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Public setter for the {@link PlatformTransactionManager}.
*
* @param transactionManager the transaction manager to set
*/
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* @param itemReader the itemReader to set
*/
public void setItemReader(ItemReader itemReader) {
this.itemReader = itemReader;
}
/**
* @param itemWriter the itemWriter to set
*/
public void setItemWriter(ItemWriter itemWriter) {
this.itemWriter = itemWriter;
}
public void setItemSkipPolicy(ItemSkipPolicy itemSkipPolicy) {
this.itemSkipPolicy = itemSkipPolicy;
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.execution.launch;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* Mock {@link ItemWriter} that will throw an exception when a certain
* number of items have been written.
*/
public class EmptyItemWriter implements ItemWriter, InitializingBean {
private boolean failed = false;
// point at which to fail...
private int failurePoint = Integer.MAX_VALUE;
protected Log logger = LogFactory.getLog(EmptyItemWriter.class);
List list;
public void afterPropertiesSet() throws Exception {
TransactionAwareProxyFactory factory = new TransactionAwareProxyFactory(new ArrayList());
list = (List) factory.createInstance();
}
public void setFailurePoint(int failurePoint) {
this.failurePoint = failurePoint;
}
public void write(Object data) {
if (!failed && list.size() == failurePoint) {
failed = true;
throw new RuntimeException("Failed processing: [" + data + "]");
}
logger.info("Processing: [" + data + "]");
list.add(data);
}
public List getList() {
return list;
}
public void clear() throws ClearFailedException {
//no-op
}
public void flush() throws FlushFailedException {
//no-op
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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.execution.launch;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.core.task.TaskExecutor;
/**
* @author Lucas Ward
*
*/
public class SimpleJobLauncherTests extends TestCase {
private SimpleJobLauncher jobLauncher;
private MockControl repositoryControl = MockControl.createControl(JobRepository.class);
private Job job = new JobSupport("foo") {
public void execute(JobExecution execution) {
execution.setExitStatus(ExitStatus.FINISHED);
return;
}
};
private JobParameters jobParameters = new JobParameters();
private JobRepository jobRepository;
protected void setUp() throws Exception {
super.setUp();
jobLauncher = new SimpleJobLauncher();
jobRepository = (JobRepository) repositoryControl.getMock();
jobLauncher.setJobRepository(jobRepository);
}
public void testRun() throws Exception {
JobExecution jobExecution = new JobExecution(null);
jobRepository.createJobExecution(job, jobParameters);
repositoryControl.setReturnValue(jobExecution);
repositoryControl.replay();
jobLauncher.run(job, jobParameters);
assertEquals(ExitStatus.FINISHED, jobExecution.getExitStatus());
repositoryControl.verify();
}
public void testTaskExecutor() throws Exception {
final List list = new ArrayList();
jobLauncher.setTaskExecutor(new TaskExecutor() {
public void execute(Runnable task) {
list.add("execute");
task.run();
}
});
testRun();
assertEquals(1, list.size());
}
public void testRunWithException() throws Exception {
job = new JobSupport() {
public void execute(JobExecution execution) {
execution.setExitStatus(ExitStatus.FAILED);
throw new RuntimeException("foo");
}
};
try {
testRun();
fail("Expected RuntimeException");
}
catch (RuntimeException e) {
assertEquals("foo", e.getMessage());
}
}
public void testRunWithError() throws Exception {
job = new JobSupport() {
public void execute(JobExecution execution) {
execution.setExitStatus(ExitStatus.FAILED);
throw new Error("foo");
}
};
try {
testRun();
fail("Expected Error");
}
catch (RuntimeException e) {
assertEquals("foo", e.getCause().getMessage());
}
}
public void testInitialiseWithoutRepository() throws Exception {
try {
new SimpleJobLauncher().afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalStateException e) {
// expected
assertTrue("Message did not contain repository: " + e.getMessage(), e.getMessage().toLowerCase().contains(
"repository"));
}
}
public void testInitialiseWithRepository() throws Exception {
jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.afterPropertiesSet(); // no error
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2006-2008 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.execution.launch.support;
import junit.framework.TestCase;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier;
import org.springframework.batch.execution.launch.JobLauncher;
import org.springframework.batch.execution.launch.support.CommandLineJobRunner;
import org.springframework.batch.execution.launch.support.SystemExiter;
import org.springframework.batch.repeat.ExitStatus;
/**
* @author Lucas Ward
*
*/
public class CommandLineJobRunnerTests extends TestCase {
private static final String JOB = "org/springframework/batch/execution/bootstrap/support/job.xml";
private static final String JOB_NAME = "test-job";
private String jobPath = JOB;
private String jobName = JOB_NAME;
private String jobKey = "job.Key=myKey";
private String scheduleDate = "schedule.Date=01/23/2008";
private String vendorId = "vendor.id=33243243";
private String[] args = new String[] { jobPath, jobName, jobKey, scheduleDate, vendorId };
/*
* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
JobExecution jobExecution = new JobExecution(null, new Long(1));
ExitStatus exitStatus = ExitStatus.FINISHED;
jobExecution.setExitStatus(exitStatus);
StubJobLauncher.jobExecution = jobExecution;
StubExceptionClassifier.exception = null;
}
public void testMain() {
CommandLineJobRunner.main(args);
assertEquals(0, StubSystemExiter.getStatus());
}
public void testJobAlreadyRunning() {
StubJobLauncher.throwExecutionRunningException = true;
CommandLineJobRunner.main(args);
assertTrue(StubExceptionClassifier.exception instanceof JobExecutionAlreadyRunningException);
}
// can't test because it will cause the system to exit.
// public void testInvalidArgs(){
//
// String[] args = new String[]{jobPath, jobName};
// CommandLineJobRunner.main(args);
// }
public void testWithNoParameters() throws Throwable {
String[] args = new String[] { jobPath, jobName };
CommandLineJobRunner.main(args);
if (StubExceptionClassifier.exception != null) {
throw StubExceptionClassifier.exception;
}
assertEquals(0, StubSystemExiter.status);
assertEquals(new JobParameters(), StubJobLauncher.jobParameters);
}
protected void tearDown() throws Exception {
super.tearDown();
StubJobLauncher.tearDown();
}
public static class StubSystemExiter implements SystemExiter {
public static int status;
public void exit(int status) {
StubSystemExiter.status = status;
}
public static int getStatus() {
return status;
}
}
public static class StubJobLauncher implements JobLauncher {
public static JobExecution jobExecution;
public static boolean throwExecutionRunningException = false;
public static JobParameters jobParameters;
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
StubJobLauncher.jobParameters = jobParameters;
if (throwExecutionRunningException) {
throw new JobExecutionAlreadyRunningException("");
}
return jobExecution;
}
public static void tearDown() {
jobExecution = null;
throwExecutionRunningException = false;
jobParameters = null;
}
}
public static class StubExceptionClassifier implements ExitStatusExceptionClassifier {
public static Throwable exception;
public Object classify(Throwable throwable) {
return null;
}
public Object getDefault() {
return null;
}
public ExitStatus classifyForExitCode(Throwable throwable) {
exception = throwable;
return ExitStatus.FAILED;
}
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright 2006-2008 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.execution.launch.support;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import junit.framework.TestCase;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.execution.launch.support.DefaultJobParametersFactory;
import org.springframework.util.StringUtils;
/**
* @author Dave Syer
*
*/
public class DefaultJobParametersFactoryTests extends TestCase {
DefaultJobParametersFactory factory = new DefaultJobParametersFactory();
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
public void testGetParameters() throws Exception {
String jobKey = "job.key=myKey";
String scheduleDate = "schedule.date(date)=2008/01/23";
String vendorId = "vendor.id(long)=33243243";
String[] args = new String[] { jobKey, scheduleDate, vendorId };
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
assertEquals("myKey", props.getString("job.key"));
assertEquals(new Long(33243243L), props.getLong("vendor.id"));
Date date = dateFormat.parse("01/23/2008");
assertEquals(date, props.getDate("schedule.date"));
}
public void testGetParametersWithDateFormat() throws Exception {
String[] args = new String[] { "schedule.date(date)=2008/23/01" };
factory.setDateFormat(new SimpleDateFormat("yyyy/dd/MM"));
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
Date date = dateFormat.parse("01/23/2008");
assertEquals(date, props.getDate("schedule.date"));
}
public void testGetParametersWithBogusDate() throws Exception {
String[] args = new String[] { "schedule.date(date)=20080123" };
try {
factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
} catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain wrong date: "+message, message.contains("20080123"));
assertTrue("Message should contain format: "+message, message.contains("yyyy/MM/dd"));
}
}
public void testGetParametersWithNumberFormat() throws Exception {
String[] args = new String[] { "value(long)=1,000" };
factory.setNumberFormat(new DecimalFormat("#,###"));
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
assertEquals(1000L, props.getLong("value").longValue());
}
public void testGetParametersWithBogusLong() throws Exception {
String[] args = new String[] { "value(long)=foo" };
try {
factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
} catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain wrong number: "+message, message.contains("foo"));
assertTrue("Message should contain format: "+message, message.contains("#"));
}
}
public void testGetParametersWithDouble() throws Exception {
String[] args = new String[] { "value(long)=1.03" };
factory.setNumberFormat(new DecimalFormat("#.#"));
try {
factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
} catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain wrong number: "+message, message.contains("1.03"));
assertTrue("Message should contain 'decimal': "+message, message.contains("decimal"));
}
}
public void testGetProperties() throws Exception {
JobParameters parameters = new JobParametersBuilder().addDate("schedule.date", dateFormat.parse("01/23/2008"))
.addString("job.key", "myKey").addLong("vendor.id", new Long(33243243)).toJobParameters();
Properties props = factory.getProperties(parameters);
assertNotNull(props);
assertEquals("myKey", props.getProperty("job.key"));
assertEquals("33243243", props.getProperty("vendor.id(long)"));
assertEquals("2008/01/23", props.getProperty("schedule.date(date)"));
}
public void testEmptyArgs() {
JobParameters props = factory.getJobParameters(new Properties());
assertTrue(props.getParameters().isEmpty());
}
public void testNullArgs(){
assertEquals(new JobParameters(), factory.getJobParameters(null));
assertEquals(new Properties(), factory.getProperties(null));
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2006-2008 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.execution.launch.support;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import junit.framework.TestCase;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.execution.launch.support.ScheduledJobParametersFactory;
import org.springframework.util.StringUtils;
/**
* @author Lucas Ward
*
*/
public class ScheduledJobParametersFactoryTests extends TestCase {
ScheduledJobParametersFactory factory;
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
protected void setUp() throws Exception {
super.setUp();
factory = new ScheduledJobParametersFactory();
}
public void testGetParameters() throws Exception {
String jobKey = "job.key=myKey";
String scheduleDate = "schedule.date=2008/01/23";
String vendorId = "vendor.id=33243243";
String[] args = new String[] { jobKey, scheduleDate, vendorId };
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
assertEquals("myKey", props.getString("job.key"));
assertEquals("33243243", props.getString("vendor.id"));
Date date = dateFormat.parse("01/23/2008");
assertEquals(date, props.getDate("schedule.date"));
}
public void testGetProperties() throws Exception {
JobParameters parameters = new JobParametersBuilder().addDate("schedule.date", dateFormat.parse("01/23/2008"))
.addString("job.key", "myKey").addString("vendor.id", "33243243").toJobParameters();
Properties props = factory.getProperties(parameters);
assertNotNull(props);
assertEquals("myKey", props.getProperty("job.key"));
assertEquals("33243243", props.getProperty("vendor.id"));
assertEquals("2008/01/23", props.getProperty("schedule.date"));
}
public void testEmptyArgs() {
JobParameters props = factory.getJobParameters(new Properties());
assertTrue(props.getParameters().isEmpty());
}
public void testNullArgs(){
assertEquals(new JobParameters(), factory.getJobParameters(null));
assertEquals(new Properties(), factory.getProperties(null));
}
public void testGetParametersWithDateFormat() throws Exception {
String[] args = new String[] { "schedule.date=2008/23/01" };
factory.setDateFormat(new SimpleDateFormat("yyyy/dd/MM"));
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
Date date = dateFormat.parse("01/23/2008");
assertEquals(date, props.getDate("schedule.date"));
}
public void testGetParametersWithBogusDate() throws Exception {
String[] args = new String[] { "schedule.date=20080123" };
try {
factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
} catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain wrong date: "+message, message.contains("20080123"));
}
}
}

View File

@@ -0,0 +1,210 @@
/*
* 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.execution.launch.support;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import junit.framework.TestCase;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.runtime.JobParametersFactory;
import org.springframework.batch.execution.configuration.MapJobRegistry;
import org.springframework.batch.execution.configuration.ReferenceJobFactory;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.launch.JobLauncher;
import org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.support.PropertiesConverter;
/**
* @author Dave Syer
*
*/
public class SimpleExportedJobLauncherTests extends TestCase {
private SimpleExportedJobLauncher launcher = new SimpleExportedJobLauncher();
private MapJobRegistry jobLocator;
private List list = new ArrayList();
protected void setUp() throws Exception {
super.setUp();
launcher.setLauncher(new JobLauncher() {
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
JobExecution result = new JobExecution(null);
StepExecution stepExecution = result.createStepExecution(new StepSupport("stepName"));
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
list.add(jobParameters);
return result;
}
});
jobLocator = new MapJobRegistry();
launcher.setJobLocator(jobLocator);
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#afterPropertiesSet()}.
* @throws Exception
*/
public void testAfterPropertiesSet() throws Exception {
launcher = new SimpleExportedJobLauncher();
try {
launcher.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message does not contain 'launcher': " + message, message.toLowerCase().contains("joblauncher"));
}
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#afterPropertiesSet()}.
* @throws Exception
*/
public void testAfterPropertiesSetWithLauncher() throws Exception {
launcher = new SimpleExportedJobLauncher();
launcher.setLauncher(new JobLauncher() {
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
return null;
}
});
try {
launcher.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message does not contain 'locator': " + message, message.toLowerCase().contains("joblocator"));
}
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#getStatistics()}.
*/
public void testGetStatistics() {
Properties props = launcher.getStatistics();
assertNotNull(props);
assertEquals(0, props.entrySet().size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#getStatistics()}.
* @throws Exception
*/
public void testGetStatisticsWithContent() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
launcher.run("foo");
Properties props = launcher.getStatistics();
assertNotNull(props);
assertEquals(1, props.entrySet().size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#isRunning()}.
* @throws Exception
*/
public void testIsRunning() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
launcher.run("foo");
assertTrue(launcher.isRunning());
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#isRunning()}.
* @throws Exception
*/
public void testAlreadyRunning() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
launcher.setLauncher(new JobLauncher() {
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
throw new JobExecutionAlreadyRunningException("Bad!");
}
});
String value = launcher.run("foo");
assertTrue("Return value was not an exception: " + value, value.contains("JobExecutionAlreadyRunningException"));
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#run(java.lang.String)}.
*/
public void testRunNonExistentJob() {
String value = launcher.run("foo");
assertTrue("Return value was not an exception: " + value, value.contains("NoSuchJobException"));
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#run(java.lang.String)}.
* @throws Exception
*/
public void testRunJobWithParameters() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
String value = launcher.run("foo", "bar=spam,bucket=crap");
assertTrue(launcher.isRunning());
assertTrue("Return value was not a JobExecution: " + value, value.contains("JobExecution"));
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#run(java.lang.String)}.
* @throws Exception
*/
public void testRunJobWithParametersAndFactory() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
launcher.setJobParametersFactory(new JobParametersFactory() {
public JobParameters getJobParameters(Properties properties) {
return new JobParametersBuilder().addString("foo", "spam").toJobParameters();
}
public Properties getProperties(JobParameters params) {
return null;
}
});
launcher.run("foo", "bar=spam,bucket=crap");
assertEquals(1, list.size());
assertEquals("spam", ((JobParameters) list.get(0)).getString("foo"));
}
/**
* Test method for
* {@link org.springframework.batch.execution.launch.support.SimpleExportedJobLauncher#stop()}.
* @throws Exception
*/
public void testStop() throws Exception {
jobLocator.register(new ReferenceJobFactory(new JobSupport("foo")));
launcher.run("foo");
assertTrue(launcher.isRunning());
launcher.stop();
assertFalse(launcher.isRunning());
}
}

View File

@@ -0,0 +1,90 @@
/*
* 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.execution.launch.support;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.springframework.batch.execution.launch.support.ExitCodeMapper;
import org.springframework.batch.execution.launch.support.SimpleJvmExitCodeMapper;
import org.springframework.batch.repeat.ExitStatus;
public class SimpleJvmExitCodeMapperTests extends TestCase {
private SimpleJvmExitCodeMapper ecm;
private SimpleJvmExitCodeMapper ecm2;
protected void setUp() throws Exception {
ecm = new SimpleJvmExitCodeMapper();
Map ecmMap = new HashMap();
ecmMap.put("MY_CUSTOM_CODE", new Integer(3));
ecm.setMapping(ecmMap);
ecm2 = new SimpleJvmExitCodeMapper();
Map ecm2Map = new HashMap();
ecm2Map.put(ExitStatus.FINISHED.getExitCode(), new Integer(-1));
ecm2Map.put(ExitStatus.FAILED.getExitCode(), new Integer(-2));
ecm2Map.put(ExitCodeMapper.JOB_NOT_PROVIDED, new Integer(-3));
ecm2Map.put(ExitCodeMapper.NO_SUCH_JOB, new Integer(-3));
ecm2.setMapping(ecm2Map);
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testGetExitCodeWithpPredefinedCodes() {
assertEquals(
ecm.getExitCode(ExitStatus.FINISHED.getExitCode()),
ExitCodeMapper.JVM_EXITCODE_COMPLETED);
assertEquals(
ecm.getExitCode(ExitStatus.FAILED.getExitCode()),
ExitCodeMapper.JVM_EXITCODE_GENERIC_ERROR);
assertEquals(
ecm.getExitCode(ExitCodeMapper.JOB_NOT_PROVIDED),
ExitCodeMapper.JVM_EXITCODE_JOB_ERROR);
assertEquals(
ecm.getExitCode(ExitCodeMapper.NO_SUCH_JOB),
ExitCodeMapper.JVM_EXITCODE_JOB_ERROR);
}
public void testGetExitCodeWithPredefinedCodesOverridden() {
System.out.println(ecm2.getExitCode(ExitStatus.FINISHED.getExitCode()));
assertEquals(
ecm2.getExitCode(ExitStatus.FINISHED.getExitCode()), -1);
assertEquals(
ecm2.getExitCode(ExitStatus.FAILED.getExitCode()), -2);
assertEquals(
ecm2.getExitCode(ExitCodeMapper.JOB_NOT_PROVIDED), -3);
assertEquals(
ecm2.getExitCode(ExitCodeMapper.NO_SUCH_JOB), -3);
}
public void testGetExitCodeWithCustomCode() {
assertEquals(ecm.getExitCode("MY_CUSTOM_CODE"),3);
}
public void testGetExitCodeWithDefaultCode() {
assertEquals(
ecm.getExitCode("UNDEFINED_CUSTOM_CODE"),
ExitCodeMapper.JVM_EXITCODE_GENERIC_ERROR);
}
}

View File

@@ -0,0 +1,54 @@
package org.springframework.batch.execution.launch.support;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.execution.launch.JobLauncher;
/**
* Mock Job Launcher. Normally, something like EasyMock would
* be used to mock an interface, however, because of the nature
* of launching a batch job from the command line, the mocked
* class cannot be injected.
*
* @author Lucas Ward
*
*/
public class StubJobLauncher implements JobLauncher {
public static final int RUN_NO_ARGS = 0;
public static final int RUN_JOB_NAME = 1;
public static final int RUN_JOB_IDENTIFIER =2 ;
private int lastRunCalled = RUN_NO_ARGS;
private JobExecution returnValue = null;
private boolean isRunning = false;
public boolean isRunning() {
return isRunning;
}
public JobExecution run(Job job, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException {
lastRunCalled = RUN_JOB_IDENTIFIER;
return returnValue;
}
public void stop() {
}
public void setReturnValue(JobExecution returnValue){
this.returnValue = returnValue;
}
public void setIsRunning(boolean isRunning){
this.isRunning = isRunning;
}
public int getLastRunCalled(){
return lastRunCalled;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2006-2008 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.execution.listener;
import org.easymock.MockControl;
import org.springframework.batch.core.ChunkListener;
import junit.framework.TestCase;
/**
* @author Lucas Ward
*
*/
public class CompositeChunkListenerTests extends TestCase {
MockControl listenerControl = MockControl.createControl(ChunkListener.class);
ChunkListener listener;
CompositeChunkListener compositeListener;
protected void setUp() throws Exception {
super.setUp();
listener = (ChunkListener)listenerControl.getMock();
compositeListener = new CompositeChunkListener();
compositeListener.register(listener);
}
public void testBeforeChunk(){
listener.beforeChunk();
listenerControl.replay();
compositeListener.beforeChunk();
listenerControl.verify();
}
public void testAfterChunk(){
listener.afterChunk();
listenerControl.replay();
compositeListener.afterChunk();
listenerControl.verify();
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2006-2008 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.execution.listener;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.ItemReadListener;
/**
* @author Lucas Ward
*
*/
public class CompositeItemReadListenerTests extends TestCase {
MockControl listenerControl = MockControl.createControl(ItemReadListener.class);
ItemReadListener listener;
CompositeItemReadListener compositeListener;
protected void setUp() throws Exception {
super.setUp();
listener = (ItemReadListener)listenerControl.getMock();
compositeListener = new CompositeItemReadListener();
compositeListener.register(listener);
}
public void testBeforeRead(){
listener.beforeRead();
listenerControl.replay();
compositeListener.beforeRead();
listenerControl.verify();
}
public void testAfterRead(){
Object item = new Object();
listener.afterRead(item);
listenerControl.replay();
compositeListener.afterRead(item);
listenerControl.verify();
}
public void testOnReadError(){
Exception ex = new Exception();
listener.onReadError(ex);
listenerControl.replay();
compositeListener.onReadError(ex);
listenerControl.verify();
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2006-2008 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.execution.listener;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.ItemWriteListener;
/**
* @author Lucas Ward
*
*/
public class CompositeItemWriteListenerTests extends TestCase {
MockControl listenerControl = MockControl.createControl(ItemWriteListener.class);
ItemWriteListener listener;
CompositeItemWriteListener compositeListener;
protected void setUp() throws Exception {
super.setUp();
listener = (ItemWriteListener)listenerControl.getMock();
compositeListener = new CompositeItemWriteListener();
compositeListener.register(listener);
}
public void testBeforeWrite(){
Object item = new Object();
listener.beforeWrite(item);
listenerControl.replay();
compositeListener.beforeWrite(item);
listenerControl.verify();
}
public void testAfterWrite(){
listener.afterWrite();
listenerControl.replay();
compositeListener.afterWrite();
listenerControl.verify();
}
public void testOnWriteError(){
Object item = new Object();
Exception ex = new Exception();
listener.onWriteError(ex, item);
listenerControl.replay();
compositeListener.onWriteError(ex, item);
listenerControl.verify();
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.execution.listener;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobListener;
import org.springframework.batch.core.listener.JobListenerSupport;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.listener.CompositeJobListener;
/**
* @author Dave Syer
*
*/
public class CompositeJobListenerTests extends TestCase {
private CompositeJobListener listener = new CompositeJobListener();
private List list = new ArrayList();
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeJobListener#setListeners(org.springframework.batch.core.JobListener[])}.
*/
public void testSetListeners() {
listener.setListeners(new JobListener[] { new JobListenerSupport() {
public void afterJob(JobExecution jobExecution) {
list.add("fail");
}
}, new JobListenerSupport() {
public void afterJob(JobExecution jobExecution) {
list.add("continue");
}
} });
listener.afterJob(null);
assertEquals(2, list.size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeJobListener#registerListener(org.springframework.batch.core.JobListener)}.
*/
public void testSetListener() {
listener.register(new JobListenerSupport() {
public void afterJob(JobExecution jobExecution) {
list.add("fail");
}
});
listener.afterJob(null);
assertEquals(1, list.size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeJobListener#beforeJob(JobExecution)}.
*/
public void testOpen() {
listener.register(new JobListenerSupport() {
public void beforeJob(JobExecution stepExecution) {
list.add("foo");
}
});
listener.beforeJob(new JobExecution(new JobInstance(new Long(11L), null, new JobSupport())));
assertEquals(1, list.size());
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.execution.listener;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.listener.StepListenerSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.repeat.ExitStatus;
/**
* @author Dave Syer
*
*/
public class CompositeStepListenerTests extends TestCase {
private CompositeStepListener listener = new CompositeStepListener();
private List list = new ArrayList();
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeStepListener#setListeners(org.springframework.batch.core.StepListener[])}.
*/
public void testSetListeners() {
listener.setListeners(new StepListener[] { new StepListenerSupport() {
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("fail");
return ExitStatus.FAILED;
}
}, new StepListenerSupport() {
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("continue");
return ExitStatus.CONTINUABLE;
}
} });
assertFalse(listener.afterStep(null).isContinuable());
assertEquals(2, list.size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeStepListener#registerListener(org.springframework.batch.core.StepListener)}.
*/
public void testSetListener() {
listener.register(new StepListenerSupport() {
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("fail");
return ExitStatus.FAILED;
}
});
assertFalse(listener.afterStep(null).isContinuable());
assertEquals(1, list.size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeStepListener#beforeStep(StepExecution)}.
*/
public void testOpen() {
listener.register(new StepListenerSupport() {
public void beforeStep(StepExecution stepExecution) {
list.add("foo");
}
});
listener.beforeStep(new StepExecution(new StepSupport("foo"), null));
assertEquals(1, list.size());
}
/**
* Test method for
* {@link org.springframework.batch.execution.listener.CompositeStepListener#beforeStep(StepExecution)}.
*/
public void testOnError() {
listener.register(new StepListenerSupport() {
public ExitStatus onErrorInStep(StepExecution stepExecution, Throwable e) {
list.add("foo");
return null;
}
});
listener.onErrorInStep(null, new RuntimeException());
assertEquals(1, list.size());
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2006-2008 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.execution.repository;
import javax.sql.DataSource;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
/**
* @author Lucas Ward
*
*/
public class JobRepositoryFactoryBeanTests extends TestCase{
JobRepositoryFactoryBean factory;
MockControl incrementerControl = MockControl.createControl(DataFieldMaxValueIncrementerFactory.class);
DataFieldMaxValueIncrementerFactory incrementerFactory;
DataSource dataSource;
protected void setUp() throws Exception {
super.setUp();
factory = new JobRepositoryFactoryBean();
MockControl dataSourceControl = MockControl.createControl(DataSource.class);
dataSource = (DataSource)dataSourceControl.getMock();
factory.setDataSource(dataSource);
incrementerFactory = (DataFieldMaxValueIncrementerFactory)incrementerControl.getMock();
factory.setIncrementerFactory(incrementerFactory);
}
public void testNoDatabaseType() throws Exception{
try{
factory.afterPropertiesSet();
fail();
}
catch(IllegalArgumentException ex){
//expected
}
}
public void testInvalidDatabaseType() throws Exception{
factory.setDatabaseType("invalid type");
try{
factory.afterPropertiesSet();
fail();
}
catch(IllegalArgumentException ex){
//expected
}
}
public void testCreateRepository() throws Exception{
String databaseType = "databaseType";
factory.setDatabaseType(databaseType);
incrementerFactory.getIncrementer(databaseType, "BATCH_JOB_SEQ");
incrementerControl.setReturnValue(new StubIncrementer());
incrementerFactory.getIncrementer(databaseType, "BATCH_JOB_EXECUTION_SEQ");
incrementerControl.setReturnValue(new StubIncrementer());
incrementerFactory.getIncrementer(databaseType, "BATCH_STEP_EXECUTION_SEQ");
incrementerControl.setReturnValue(new StubIncrementer());
incrementerControl.replay();
factory.getObject();
incrementerControl.verify();
}
private class StubIncrementer implements DataFieldMaxValueIncrementer {
public int nextIntValue() throws DataAccessException {
return 0;
}
public long nextLongValue() throws DataAccessException {
return 0;
}
public String nextStringValue() throws DataAccessException {
return null;
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.execution.repository;
import java.util.List;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.repository.dao.StepExecutionDao;
import org.springframework.batch.item.ExecutionContext;
public class MockStepDao implements StepExecutionDao {
private List newSteps;
public List findStepInstances(JobInstance job) {
return newSteps;
}
public void saveStepExecution(StepExecution stepExecution) {
}
public void updateStepExecution(StepExecution stepExecution) {
}
public void setStepsToReturnOnCreate(List steps) {
this.newSteps = steps;
}
public ExecutionContext findExecutionContext(StepExecution stepExecution) {
return null;
}
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
}
public StepExecution getStepExecution(JobExecution jobExecution, Step step) {
return null;
}
}

View File

@@ -0,0 +1,196 @@
package org.springframework.batch.execution.repository;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
/**
* Repository tests using JDBC DAOs (rather than mocks).
*
* @author Robert Kasanicky
*/
public class SimpleJobRepositoryIntegrationTests extends AbstractTransactionalDataSourceSpringContextTests {
protected String[] getConfigLocations() {
return new String[] { ClassUtils.addResourcePathToPackagePath(getClass(), "dao/sql-dao-test.xml") };
}
private SimpleJobRepository jobRepository;
private JobSupport job = new JobSupport("testJob");
private JobParameters jobParameters = new JobParameters();
public void setJobRepository(SimpleJobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Create two job executions for same job+parameters tuple. Check both
* executions belong to the same job instance and job.
*/
public void testCreateAndFind() throws Exception {
job.setRestartable(true);
Map stringParams = new HashMap() {
{
put("stringKey", "stringValue");
}
};
Map longParams = new HashMap() {
{
put("longKey", new Long(1));
}
};
Map doubleParams = new HashMap() {
{
put("doubleKey", new Double(1.1));
}
};
Map dateParams = new HashMap() {
{
put("dateKey", new Date(1));
}
};
JobParameters jobParams = new JobParameters(stringParams, longParams, doubleParams, dateParams);
JobExecution firstExecution = jobRepository.createJobExecution(job, jobParams);
firstExecution.setStartTime(new Date());
assertEquals(job, firstExecution.getJobInstance().getJob());
jobRepository.saveOrUpdate(firstExecution);
firstExecution.setEndTime(new Date());
jobRepository.saveOrUpdate(firstExecution);
JobExecution secondExecution = jobRepository.createJobExecution(job, jobParams);
assertEquals(firstExecution.getJobInstance(), secondExecution.getJobInstance());
assertEquals(job, secondExecution.getJobInstance().getJob());
}
/**
* Create two job executions for same job+parameters tuple. Check both
* executions belong to the same job instance and job.
*/
public void testCreateAndFindWithNoStartDate() throws Exception {
job.setRestartable(true);
JobExecution firstExecution = jobRepository.createJobExecution(job, jobParameters);
firstExecution.setEndTime(new Date());
jobRepository.saveOrUpdate(firstExecution);
JobExecution secondExecution = jobRepository.createJobExecution(job, jobParameters);
assertEquals(firstExecution.getJobInstance(), secondExecution.getJobInstance());
assertEquals(job, secondExecution.getJobInstance().getJob());
}
/**
* Non-restartable JobInstance can be run only once - attempt to run
* existing non-restartable JobInstance causes error.
*/
public void testRunNonRestartableJobInstanceTwice() throws Exception {
job.setRestartable(false);
JobExecution firstExecution = jobRepository.createJobExecution(job, jobParameters);
jobRepository.saveOrUpdate(firstExecution);
try {
jobRepository.createJobExecution(job, jobParameters);
fail();
}
catch (JobRestartException e) {
// expected
}
}
/**
* Save multiple StepExecutions for the same step and check the returned
* count and last execution are correct.
*/
public void testGetStepExecutionCountAndLastStepExecution() throws Exception {
job.setRestartable(true);
StepSupport step = new StepSupport("restartedStep");
// first execution
JobExecution firstJobExec = jobRepository.createJobExecution(job, jobParameters);
StepExecution firstStepExec = new StepExecution(step, firstJobExec);
jobRepository.saveOrUpdate(firstJobExec);
jobRepository.saveOrUpdate(firstStepExec);
assertEquals(1, jobRepository.getStepExecutionCount(firstJobExec.getJobInstance(), step));
assertEquals(firstStepExec, jobRepository.getLastStepExecution(firstJobExec.getJobInstance(), step));
// first execution failed
firstJobExec.setStartTime(new Date(4));
firstStepExec.setStartTime(new Date(5));
firstStepExec.setStatus(BatchStatus.FAILED);
firstStepExec.setEndTime(new Date(6));
jobRepository.saveOrUpdate(firstStepExec);
firstJobExec.setStatus(BatchStatus.FAILED);
firstJobExec.setEndTime(new Date(7));
jobRepository.saveOrUpdate(firstJobExec);
// second execution
JobExecution secondJobExec = jobRepository.createJobExecution(job, jobParameters);
StepExecution secondStepExec = new StepExecution(step, secondJobExec);
jobRepository.saveOrUpdate(secondJobExec);
jobRepository.saveOrUpdate(secondStepExec);
assertEquals(2, jobRepository.getStepExecutionCount(secondJobExec.getJobInstance(), step));
assertEquals(secondStepExec, jobRepository.getLastStepExecution(secondJobExec.getJobInstance(), step));
}
/**
* Save execution context and retrieve it.
*/
public void testSaveExecutionContext() throws Exception {
ExecutionContext ctx = new ExecutionContext() {
{
putLong("crashedPosition", 7);
}
};
JobExecution jobExec = jobRepository.createJobExecution(job, jobParameters);
Step step = new StepSupport("step1");
StepExecution stepExec = new StepExecution(step, jobExec);
stepExec.setExecutionContext(ctx);
jobRepository.saveOrUpdate(stepExec);
jobRepository.saveOrUpdateExecutionContext(stepExec);
StepExecution retrievedExec = jobRepository.getLastStepExecution(jobExec.getJobInstance(), step);
assertEquals(stepExec, retrievedExec);
assertEquals(ctx, retrievedExec.getExecutionContext());
}
/**
* If JobExecution is already running, exception will be thrown in attempt
* to create new execution.
*/
public void testOnlyOneJobExecutionAllowedRunning() throws Exception {
job.setRestartable(true);
jobRepository.createJobExecution(job, jobParameters);
try {
jobRepository.createJobExecution(job, jobParameters);
fail();
}
catch (JobExecutionAlreadyRunningException e) {
// expected
}
}
}

View File

@@ -0,0 +1,398 @@
/*
* 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.execution.repository;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.repository.dao.JobExecutionDao;
import org.springframework.batch.execution.repository.dao.JobInstanceDao;
import org.springframework.batch.execution.repository.dao.StepExecutionDao;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.item.ExecutionContext;
/**
* Test SimpleJobRepository. The majority of test cases are tested using
* EasyMock, however, there were some issues with using it for the stepExecutionDao when
* testing finding or creating steps, so an actual mock class had to be written.
*
* @author Lucas Ward
*
*/
public class SimpleJobRepositoryTests extends TestCase {
SimpleJobRepository jobRepository;
JobSupport jobConfiguration;
JobParameters jobParameters;
Step stepConfiguration1;
Step stepConfiguration2;
MockControl jobExecutionDaoControl = MockControl.createControl(JobExecutionDao.class);
MockControl jobInstanceDaoControl = MockControl.createControl(JobInstanceDao.class);
MockControl stepExecutionDaoControl = MockControl.createControl(StepExecutionDao.class);
JobExecutionDao jobExecutionDao;
JobInstanceDao jobInstanceDao;
StepExecutionDao stepExecutionDao;
MockStepDao mockStepDao = new MockStepDao();
JobInstance databaseJob;
String databaseStep1;
String databaseStep2;
List steps;
ExecutionContext executionContext;
public void setUp() throws Exception {
jobExecutionDao = (JobExecutionDao) jobExecutionDaoControl.getMock();
jobInstanceDao = (JobInstanceDao) jobInstanceDaoControl.getMock();
stepExecutionDao = (StepExecutionDao) stepExecutionDaoControl.getMock();
jobRepository = new SimpleJobRepository(jobInstanceDao, jobExecutionDao, stepExecutionDao);
jobParameters = new JobParametersBuilder().toJobParameters();
jobConfiguration = new JobSupport();
jobConfiguration.setBeanName("RepositoryTest");
jobConfiguration.setRestartable(true);
stepConfiguration1 = new StepSupport("TestStep1");
stepConfiguration2 = new StepSupport("TestStep2");
List stepConfigurations = new ArrayList();
stepConfigurations.add(stepConfiguration1);
stepConfigurations.add(stepConfiguration2);
jobConfiguration.setSteps(stepConfigurations);
databaseJob = new JobInstance(new Long(1), jobParameters, jobConfiguration);
databaseStep1 = "dbStep1";
databaseStep2 = "dbStep2";
steps = new ArrayList();
steps.add(databaseStep1);
steps.add(databaseStep2);
executionContext = new ExecutionContext();
}
/*
* Test a restartable job, that has not been run before.
*/
public void testCreateRestartableJob() throws Exception {
// List jobExecutions = new ArrayList();
//
// jobInstanceDao.findJobInstances(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(jobExecutions);
// jobInstanceDao.createJobInstance(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(databaseJob);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep1");
//// stepInstanceDaoControl.setReturnValue(databaseStep1);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep2");
//// stepInstanceDaoControl.setReturnValue(databaseStep2);
// jobExecutionDao.saveJobExecution(new JobExecution(databaseJob));
// jobExecutionDaoControl.setMatcher(new ArgumentsMatcher() {
// public boolean matches(Object[] expected, Object[] actual) {
// return ((JobExecution) actual[0]).getJobInstance().equals(databaseJob);
// }
//
// public String toString(Object[] arguments) {
// return "" + arguments[0];
// }
// });
// stepExecutionDaoControl.replay();
//// stepInstanceDaoControl.replay();
// jobExecutionDaoControl.replay();
// jobInstanceDaoControl.replay();
// JobInstance job = jobRepository.createJobExecution(jobConfiguration, jobParameters).getJobInstance();
// assertTrue(job.equals(databaseJob));
// List jobSteps = job.getStepNames();
// Iterator it = jobSteps.iterator();
// String step = (String) it.next();
// assertTrue(step.equals(databaseStep1));
// step = (String) it.next();
// assertTrue(step.equals(databaseStep2));
}
public void testRestartedJob() throws Exception {
// final List executions = new ArrayList();
// JobExecution execution = databaseJob.createJobExecution();
// executions.add(execution);
// // For this test it is important that the execution is finished
// // and the executions in the list contain one with an end date
// execution.setEndTime(new Date(System.currentTimeMillis()));
//
// StepExecution databaseStep1Exec = new StepExecution(databaseStep1, execution, new Long(1));
// StepExecution databaseStep2Exec = new StepExecution(databaseStep2, execution, new Long(2));
//
// List jobs = new ArrayList();
// jobInstanceDao.findJobInstances(jobConfiguration.getName(), jobParameters);
// jobs.add(databaseJob);
// jobInstanceDaoControl.setReturnValue(jobs);
//// stepInstanceDao.findStepInstance(databaseJob, "TestStep1");
//// stepInstanceDaoControl.setReturnValue(databaseStep1);
//// stepExecutionDao.getLastStepExecution(databaseStep1, jobExecution);
//// stepExecutionDaoControl.setReturnValue(databaseStep1Exec);
// stepExecutionDao.findExecutionContext(databaseStep1Exec);
// stepExecutionDaoControl.setReturnValue(executionContext);
// //stepExecutionDao.getStepExecutionCount(databaseStep1);
//// stepExecutionDaoControl.setReturnValue(1);
//// stepInstanceDao.findStepInstance(databaseJob, "TestStep2");
//// stepInstanceDaoControl.setReturnValue(databaseStep2);
//// stepExecutionDao.getLastStepExecution(databaseStep2, jobExecution);
//// stepExecutionDaoControl.setReturnValue(databaseStep2Exec);
// stepExecutionDao.findExecutionContext(databaseStep2Exec);
// stepExecutionDaoControl.setReturnValue(executionContext);
//// stepExecutionDao.getStepExecutionCount(databaseStep2);
//// stepExecutionDaoControl.setReturnValue(1);
// stepExecutionDaoControl.replay();
//// stepInstanceDaoControl.replay();
// jobExecutionDao.getJobExecutionCount(databaseJob);
// jobExecutionDaoControl.setReturnValue(1);
// jobExecutionDao.findJobExecutions(databaseJob);
// jobExecutionDaoControl.setReturnValue(executions);
// jobExecutionDao.saveJobExecution(new JobExecution(databaseJob));
// jobExecutionDaoControl.setMatcher(new ArgumentsMatcher() {
// public boolean matches(Object[] expected, Object[] actual) {
// JobExecution execution = (JobExecution) actual[0];
// return execution.getJobInstance().equals(databaseJob);
// }
//
// public String toString(Object[] arguments) {
// return "" + arguments[0];
// }
// });
// jobExecutionDaoControl.setVoidCallable();
// jobExecutionDaoControl.replay();
// jobInstanceDaoControl.replay();
// JobInstance job = jobRepository.createJobExecution(jobConfiguration, jobParameters).getJobInstance();
// assertTrue(job.equals(databaseJob));
// List jobSteps = job.getStepNames();
// Iterator it = jobSteps.iterator();
// String step = (String) it.next();
// assertTrue(step.equals(databaseStep1));
//// assertTrue(step.getStepExecutionCount() == 1);
// step = (String) it.next();
// assertTrue(step.equals(databaseStep2));
//// assertTrue(step.getStepExecutionCount() == 1);
}
public void testCreateNonRestartableJob() throws Exception {
// List jobs = new ArrayList();
// jobConfiguration.setRestartable(false);
//
// jobInstanceDao.findJobInstances(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(jobs);
// jobInstanceDao.createJobInstance(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(databaseJob);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep1");
//// stepInstanceDaoControl.setReturnValue(databaseStep1);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep2");
//// stepInstanceDaoControl.setReturnValue(databaseStep2);
// jobExecutionDao.saveJobExecution(new JobExecution(databaseJob));
// jobExecutionDaoControl.setMatcher(new ArgumentsMatcher() {
// public boolean matches(Object[] expected, Object[] actual) {
// return ((JobExecution) actual[0]).getJobInstance().equals(databaseJob);
// }
//
// public String toString(Object[] arguments) {
// return "" + arguments[0];
// }
// });
// stepExecutionDaoControl.replay();
//// stepInstanceDaoControl.replay();
// jobExecutionDaoControl.replay();
// jobInstanceDaoControl.replay();
// JobInstance job = jobRepository.createJobExecution(jobConfiguration, jobParameters).getJobInstance();
// assertTrue(job.equals(databaseJob));
// List jobSteps = job.getStepNames();
// Iterator it = jobSteps.iterator();
// String step = (String) it.next();
// assertTrue(step.equals(databaseStep1));
// step = (String) it.next();
// assertTrue(step.equals(databaseStep2));
}
public void testSaveOrUpdateInvalidJobExecution() {
// failure scenario - must have job ID
JobExecution jobExecution = new JobExecution(null);
try {
jobRepository.saveOrUpdate(jobExecution);
fail();
}
catch (Exception ex) {
// expected
}
}
public void testSaveOrUpdateValidJobExecution() throws Exception {
JobExecution jobExecution = new JobExecution(new JobInstance(new Long(1), jobParameters, jobConfiguration));
// new execution - call save on job dao
jobExecutionDao.saveJobExecution(jobExecution);
jobExecutionDaoControl.replay();
jobRepository.saveOrUpdate(jobExecution);
jobExecutionDaoControl.reset();
// update existing execution
jobExecution.setId(new Long(5));
jobExecutionDao.updateJobExecution(jobExecution);
jobExecutionDaoControl.replay();
jobRepository.saveOrUpdate(jobExecution);
}
public void testSaveOrUpdateStepExecutionException() {
StepExecution stepExecution = new StepExecution(new StepSupport("stepName"), null, null);
// failure scenario -- no step id set.
try {
jobRepository.saveOrUpdate(stepExecution);
fail();
}
catch (Exception ex) {
// expected
}
}
/*
* Test to ensure that if a StepDao returns invalid restart data, it is
* corrected.
*/
public void testCreateStepsFixesInvalidExecutionContext() throws Exception {
// List jobs = new ArrayList();
//
// jobInstanceDao.findJobInstances(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(jobs);
// jobInstanceDao.createJobInstance(jobConfiguration.getName(), jobParameters);
// jobInstanceDaoControl.setReturnValue(databaseJob);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep1");
//// stepInstanceDaoControl.setReturnValue(databaseStep1);
//// stepInstanceDao.createStepInstance(databaseJob, "TestStep2");
//// stepInstanceDaoControl.setReturnValue(databaseStep2);
// jobExecutionDao.saveJobExecution(new JobExecution(databaseJob));
// jobExecutionDaoControl.setMatcher(new ArgumentsMatcher() {
// public boolean matches(Object[] expected, Object[] actual) {
// return ((JobExecution) actual[0]).getJobInstance().equals(databaseJob);
// }
//
// public String toString(Object[] arguments) {
// return "" + arguments[0];
// }
// });
// stepExecutionDaoControl.replay();
//// stepInstanceDaoControl.replay();
// jobExecutionDaoControl.replay();
// jobInstanceDaoControl.replay();
// JobInstance job = jobRepository.createJobExecution(jobConfiguration, jobParameters).getJobInstance();
// List jobSteps = job.getStepNames();
// Iterator it = jobSteps.iterator();
// String step = (String) it.next();
// assertTrue(step.equals(databaseStep1));
// step = (String) it.next();
// assertTrue(step.equals(databaseStep2));
}
public void testFindStepsFixesInvalidExecutionContext() throws Exception {
// StepExecution databaseStep1Exec = new StepExecution(databaseStep1, null, new Long(1));
// StepExecution databaseStep2Exec = new StepExecution(databaseStep2, null, new Long(2));
//
// List jobs = new ArrayList();
// jobInstanceDao.findJobInstances(jobConfiguration.getName(), jobParameters);
// jobs.add(databaseJob);
// jobInstanceDaoControl.setReturnValue(jobs);
//// stepInstanceDao.findStepInstance(databaseJob, "TestStep1");
//// stepInstanceDaoControl.setReturnValue(databaseStep1);
//// stepExecutionDao.getLastStepExecution(databaseStep1, null);
//// stepExecutionDaoControl.setReturnValue(databaseStep1Exec);
// stepExecutionDao.findExecutionContext(databaseStep1Exec);
// stepExecutionDaoControl.setReturnValue(executionContext);
//// stepExecutionDao.getStepExecutionCount(databaseStep1);
//// stepExecutionDaoControl.setReturnValue(1);
//// stepInstanceDao.findStepInstance(databaseJob, "TestStep2");
//// stepInstanceDaoControl.setReturnValue(databaseStep2);
//// stepExecutionDao.getLastStepExecution(databaseStep2, null);
//// stepExecutionDaoControl.setReturnValue(databaseStep2Exec);
// stepExecutionDao.findExecutionContext(databaseStep2Exec);
// stepExecutionDaoControl.setReturnValue(executionContext);
//// stepExecutionDao.getStepExecutionCount(databaseStep2);
//// stepExecutionDaoControl.setReturnValue(1);
// stepExecutionDaoControl.replay();
//// stepInstanceDaoControl.replay();
//
// jobExecutionDao.getJobExecutionCount(databaseJob);
// jobExecutionDaoControl.setReturnValue(1);
// jobExecutionDao.findJobExecutions(databaseJob);
// jobExecutionDaoControl.setReturnValue(new ArrayList());
// jobExecutionDao.saveJobExecution(new JobExecution(databaseJob));
// jobExecutionDaoControl.setMatcher(new ArgumentsMatcher() {
// public boolean matches(Object[] expected, Object[] actual) {
// return ((JobExecution) actual[0]).getJobInstance().equals(databaseJob);
// }
//
// public String toString(Object[] arguments) {
// return "" + arguments[0];
// }
// });
// jobExecutionDaoControl.replay();
// jobInstanceDaoControl.replay();
// JobInstance job = jobRepository.createJobExecution(jobConfiguration, jobParameters).getJobInstance();
// assertTrue(job.equals(databaseJob));
// List jobSteps = job.getStepNames();
// Iterator it = jobSteps.iterator();
// String step = (String) it.next();
// assertTrue(step.equals(databaseStep1));
//// assertTrue(step.getLastExecution().getExecutionContext().isEmpty());
// step = (String) it.next();
//// assertTrue(step.getLastExecution().getExecutionContext().isEmpty());
// assertTrue(step.equals(databaseStep2));
}
}

View File

@@ -0,0 +1,287 @@
/*
* 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.execution.repository.dao;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
/**
* @author Dave Syer
*
*/
public abstract class AbstractJobDaoTests extends AbstractTransactionalDataSourceSpringContextTests {
protected JobInstanceDao jobInstanceDao;
protected JobExecutionDao jobExecutionDao;
protected JobParameters jobParameters = new JobParametersBuilder().addString("job.key", "jobKey").addLong("long",
new Long(1)).addDate("date", new Date(7)).addDouble("double", new Double(7.7)).toJobParameters();
protected JobInstance jobInstance;
protected Job job;
protected JobExecution jobExecution;
protected Date jobExecutionStartTime = new Date(System.currentTimeMillis());
protected String[] getConfigLocations() {
return new String[] { ClassUtils.addResourcePathToPackagePath(getClass(), "sql-dao-test.xml") };
}
/**
* Because AbstractTransactionalSpringContextTests is used, this method will
* be called by Spring to set the JobRepository.
*/
public void setJobInstanceDao(JobInstanceDao jobInstanceDao) {
this.jobInstanceDao = jobInstanceDao;
}
public void setJobExecutionDao(JobExecutionDao jobExecutionDao) {
this.jobExecutionDao = jobExecutionDao;
}
protected void onSetUpInTransaction() throws Exception {
job = new JobSupport("Job1");
// Create job.
jobInstance = jobInstanceDao.createJobInstance(job, jobParameters);
// Create an execution
jobExecutionStartTime = new Date(System.currentTimeMillis());
jobExecution = new JobExecution(jobInstance);
jobExecution.setStartTime(jobExecutionStartTime);
jobExecution.setStatus(BatchStatus.STARTED);
jobExecutionDao.saveJobExecution(jobExecution);
}
public void testVersionIsNotNullForJob() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_JOB_INSTANCE where JOB_INSTANCE_ID="
+ jobInstance.getId());
assertEquals(0, version);
}
public void testVersionIsNotNullForJobExecution() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_JOB_EXECUTION where JOB_EXECUTION_ID="
+ jobExecution.getId());
assertEquals(0, version);
}
public void testFindNonExistentJob() {
// No job should be found since it hasn't been created.
JobInstance jobInstance = jobInstanceDao.getJobInstance(new JobSupport("nonexistentJob"), jobParameters);
assertNull(jobInstance);
}
public void testFindJob() {
JobInstance instance = jobInstanceDao.getJobInstance(job, jobParameters);
assertNotNull(instance);
assertTrue(jobInstance.equals(instance));
assertEquals(jobParameters, instance.getJobParameters());
}
public void testFindJobWithNullRuntime() {
try {
jobInstanceDao.getJobInstance(null, null);
fail();
}
catch (IllegalArgumentException ex) {
// expected
}
}
/**
* Test that ensures that if you create a job with a given name, then find a
* job with the same name, but other pieces of the identifier different, you
* get no result, not the existing one.
*/
public void testCreateJobWithExistingName() {
Job scheduledJob = new JobSupport("ScheduledJob");
jobInstanceDao.createJobInstance(scheduledJob, jobParameters);
// Modifying the key should bring back a completely different
// JobInstance
JobParameters tempProps = new JobParametersBuilder().addString("job.key", "testKey1").toJobParameters();
JobInstance instance;
instance = jobInstanceDao.getJobInstance(scheduledJob, jobParameters);
assertNotNull(instance);
assertEquals(jobParameters, instance.getJobParameters());
instance = jobInstanceDao.getJobInstance(scheduledJob, tempProps);
assertNull(instance);
}
public void testUpdateJobExecution() {
jobExecution.setStatus(BatchStatus.COMPLETED);
jobExecution.setExitStatus(ExitStatus.FINISHED);
jobExecution.setEndTime(new Date(System.currentTimeMillis()));
jobExecutionDao.updateJobExecution(jobExecution);
List executions = jobExecutionDao.findJobExecutions(jobInstance);
assertEquals(executions.size(), 1);
validateJobExecution(jobExecution, (JobExecution) executions.get(0));
}
public void testSaveJobExecution() {
List executions = jobExecutionDao.findJobExecutions(jobInstance);
assertEquals(executions.size(), 1);
validateJobExecution(jobExecution, (JobExecution) executions.get(0));
}
public void testUpdateInvalidJobExecution() {
// id is invalid
JobExecution execution = new JobExecution(jobInstance, new Long(29432));
try {
jobExecutionDao.updateJobExecution(execution);
fail("Expected NoSuchBatchDomainObjectException");
}
catch (NoSuchObjectException ex) {
// expected
}
}
public void testUpdateNullIdJobExection() {
JobExecution execution = new JobExecution(jobInstance);
try {
jobExecutionDao.updateJobExecution(execution);
fail();
}
catch (IllegalArgumentException ex) {
// expected
}
}
public void testIncrementExecutionCount() {
// 1 JobExection already added in setup
assertEquals(jobExecutionDao.getJobExecutionCount(jobInstance), 1);
// Save new JobExecution for same job
JobExecution testJobExecution = new JobExecution(jobInstance);
jobExecutionDao.saveJobExecution(testJobExecution);
// JobExecutionCount should be incremented by 1
assertEquals(jobExecutionDao.getJobExecutionCount(jobInstance), 2);
}
public void testZeroExecutionCount() {
JobInstance testJob = jobInstanceDao.createJobInstance(new JobSupport("test"), new JobParameters());
// no jobExecutions saved for new job, count should be 0
assertEquals(jobExecutionDao.getJobExecutionCount(testJob), 0);
}
public void testJobWithSimpleJobIdentifier() throws Exception {
Job testJob = new JobSupport("test");
// Create job.
jobInstance = jobInstanceDao.createJobInstance(testJob, jobParameters);
List jobs = jdbcTemplate.queryForList("SELECT * FROM BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=?",
new Object[] { jobInstance.getId() });
assertEquals(1, jobs.size());
assertEquals("test", ((Map) jobs.get(0)).get("JOB_NAME"));
}
public void testJobWithDefaultJobIdentifier() throws Exception {
Job testDefaultJob = new JobSupport("testDefault");
// Create job.
jobInstance = jobInstanceDao.createJobInstance(testDefaultJob, jobParameters);
JobInstance instance = jobInstanceDao.getJobInstance(testDefaultJob, jobParameters);
assertNotNull(instance);
assertEquals(jobParameters.getString("job.key"), instance.getJobParameters().getString(
"job.key"));
}
public void testFindJobExecutions() {
List results = jobExecutionDao.findJobExecutions(jobInstance);
assertEquals(results.size(), 1);
validateJobExecution(jobExecution, (JobExecution) results.get(0));
}
public void testFindJobsWithProperties() throws Exception {
}
private void validateJobExecution(JobExecution lhs, JobExecution rhs) {
// equals operator only checks id
assertEquals(lhs, rhs);
assertEquals(lhs.getStartTime(), rhs.getStartTime());
assertEquals(lhs.getEndTime(), rhs.getEndTime());
assertEquals(lhs.getStatus(), rhs.getStatus());
assertEquals(lhs.getExitStatus(), rhs.getExitStatus());
}
public void testGetLastJobExecution() {
JobExecution lastExecution = new JobExecution(jobInstance);
lastExecution.setStatus(BatchStatus.STARTED);
int JUMP_INTO_FUTURE = 1000; // makes sure start time is 'greatest'
lastExecution.setStartTime(new Date(System.currentTimeMillis() + JUMP_INTO_FUTURE));
jobExecutionDao.saveJobExecution(lastExecution);
assertEquals(lastExecution, jobExecutionDao.getLastJobExecution(jobInstance));
}
/**
* Trying to create instance twice for the same job+parameters causes error
*/
public void testCreateDuplicateInstance() {
jobParameters = new JobParameters();
jobInstanceDao.createJobInstance(job, jobParameters);
try {
jobInstanceDao.createJobInstance(job, jobParameters);
fail();
}
catch (IllegalStateException e) {
// expected
}
}
}

View File

@@ -0,0 +1,225 @@
/*
* 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.execution.repository.dao;
import java.util.Date;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
/**
* Tests for step persistence (StepInstanceDao and StepExecutionDao). Because it is very reasonable to assume that there is a
* foreign key constraint on the JobId of a step, the JobDao is used to create
* jobs, to have an id for creating steps.
*
* @author Lucas Ward
* @author Dave Syer
*/
public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSourceSpringContextTests {
protected JobInstanceDao jobInstanceDao;
protected StepExecutionDao stepExecutionDao;
protected JobExecutionDao jobExecutionDao;
protected JobInstance jobInstance;
protected Step step1;
protected Step step2;
protected StepExecution stepExecution;
protected JobExecution jobExecution;
protected JobParameters jobParameters = new JobParameters();
protected ExecutionContext executionContext;
public void setJobInstanceDao(JobInstanceDao jobInstanceDao) {
this.jobInstanceDao = jobInstanceDao;
}
public void setStepExecutionDao(StepExecutionDao stepExecutionDao) {
this.stepExecutionDao = stepExecutionDao;
}
public void setJobExecutionDao(JobExecutionDao jobExecutionDao) {
this.jobExecutionDao = jobExecutionDao;
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractSingleSpringContextTests#getConfigLocations()
*/
protected String[] getConfigLocations() {
return new String[] { ClassUtils.addResourcePathToPackagePath(getClass(), "sql-dao-test.xml") };
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
*/
protected void onSetUpInTransaction() throws Exception {
Job job = new JobSupport("TestJob");
jobInstance = jobInstanceDao.createJobInstance(job, jobParameters);
step1 = new StepSupport("TestStep1");
step2 = new StepSupport("TestStep2");
jobExecution = new JobExecution(jobInstance);
jobExecutionDao.saveJobExecution(jobExecution);
stepExecution = new StepExecution(step1, jobExecution, new Long(1));
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setStartTime(new Date(System.currentTimeMillis()));
stepExecutionDao.saveStepExecution(stepExecution);
executionContext = new ExecutionContext();
executionContext.putString("1", "testString1");
executionContext.putString("2", "testString2");
executionContext.putLong("3", 3);
executionContext.putDouble("4", 4.4);
}
public void testVersionIsNotNullForStepExecution() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_STEP_EXECUTION where STEP_EXECUTION_ID="
+ stepExecution.getId());
assertEquals(0, version);
}
public void testUpdateStepWithExecutionContext() {
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveOrUpdateExecutionContext(stepExecution);
ExecutionContext tempAttributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, tempAttributes);
}
public void testSaveStepExecution() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testSaveStepExecutionAndExecutionContext() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExecutionContext(executionContext);
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
stepExecutionDao.saveOrUpdateExecutionContext(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExecutionContext().getString("1"), retrievedExecution.getExecutionContext().getString("1"));
assertEquals(execution.getExecutionContext().getLong("3"), retrievedExecution.getExecutionContext().getLong("3"));
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecution() {
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setEndTime(new Date(System.currentTimeMillis()));
stepExecution.setCommitCount(5);
stepExecution.setTaskCount(5);
stepExecution.setExecutionContext(new ExecutionContext());
stepExecution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.updateStepExecution(stepExecution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step1);
assertNotNull(retrievedExecution);
assertEquals(stepExecution, retrievedExecution);
assertEquals(stepExecution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecutionWithNullId() {
StepExecution stepExecution = new StepExecution(new StepSupport("testStep"), null, null);
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
public void testUpdateStepExecutionVersion() throws Exception {
int before = stepExecution.getVersion().intValue();
stepExecutionDao.updateStepExecution(stepExecution);
int after = stepExecution.getVersion().intValue();
assertEquals("StepExecution version not updated", before + 1, after);
}
public void testUpdateStepExecutionOptimisticLocking() throws Exception {
stepExecution.incrementVersion(); // not really allowed outside dao
// code
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected OptimisticLockingFailureException");
}
catch (OptimisticLockingFailureException e) {
// expected
assertTrue("Exception message should contain step execution id: " + e.getMessage(), e.getMessage().indexOf(
"" + stepExecution.getId()) >= 0);
assertTrue("Exception message should contain step execution version: " + e.getMessage(), e.getMessage()
.indexOf("" + stepExecution.getVersion()) >= 0);
}
}
public void testSaveExecutionContext(){
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveOrUpdateExecutionContext(stepExecution);
ExecutionContext attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
executionContext.putString("newString", "newString");
executionContext.putLong("newLong", 1);
executionContext.putDouble("newDouble", 2.5);
executionContext.put("newSerializable", "serializableValue");
stepExecutionDao.saveOrUpdateExecutionContext(stepExecution);
attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
}
public void testGetStepExecution() {
assertEquals(stepExecution, stepExecutionDao.getStepExecution(jobExecution, step1));
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.execution.repository.dao;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
/**
* @author Dave Syer
*
*/
public class JdbcJobDaoQueryTests extends TestCase {
JdbcJobExecutionDao jobExecutionDao;
List list = new ArrayList();
/*
* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
jobExecutionDao = new JdbcJobExecutionDao();
jobExecutionDao.setJobExecutionIncrementer(new DataFieldMaxValueIncrementer() {
public int nextIntValue() throws DataAccessException {
return 0;
}
public long nextLongValue() throws DataAccessException {
return 0;
}
public String nextStringValue() throws DataAccessException {
return "bar";
}
});
}
public void testTablePrefix() throws Exception {
jobExecutionDao.setTablePrefix("FOO_");
jobExecutionDao.setJdbcTemplate(new JdbcTemplate() {
public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
list.add(sql);
return 1;
}
});
JobExecution jobExecution = new JobExecution(new JobInstance(new Long(11), new JobParameters(), new JobSupport(
"testJob")));
jobExecutionDao.saveJobExecution(jobExecution);
assertEquals(1, list.size());
String query = (String) list.get(0);
assertTrue("Query did not contain FOO_:" + query, query.indexOf("FOO_") >= 0);
}
}

View File

@@ -0,0 +1,32 @@
package org.springframework.batch.execution.repository.dao;
import java.util.List;
import java.util.Map;
import org.springframework.batch.repeat.ExitStatus;
public class JdbcJobDaoTests extends AbstractJobDaoTests {
public static final String LONG_STRING = "A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String ";
protected void onSetUpBeforeTransaction() throws Exception {
((JdbcJobInstanceDao) jobInstanceDao).setTablePrefix(AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX);
((JdbcJobExecutionDao) jobExecutionDao).setTablePrefix(AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX);
}
public void testUpdateJobExecutionWithLongExitCode() {
assertTrue(LONG_STRING.length() > 250);
jobExecution.setExitStatus(ExitStatus.FINISHED
.addExitDescription(LONG_STRING));
jobExecutionDao.updateJobExecution(jobExecution);
List executions = jdbcTemplate.queryForList(
"SELECT * FROM BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=?",
new Object[] { jobInstance.getId() });
assertEquals(1, executions.size());
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0))
.get("EXIT_MESSAGE"));
}
}

View File

@@ -0,0 +1,111 @@
package org.springframework.batch.execution.repository.dao;
import java.util.List;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
/**
* Unit Test of SqlStepDao that only tests prefix matching. A
* separate test is needed because all other tests hit hsql,
* while this test needs to mock JdbcTemplate to analyze the
* Sql passed in.
*
* @author Lucas Ward
*
*/
public class JdbcStepDaoPrefixTests extends TestCase {
private JdbcStepExecutionDao stepExecutionDao;
MockJdbcTemplate jdbcTemplate = new MockJdbcTemplate();
JobInstance job = new JobInstance(new Long(1), new JobParameters(), new JobSupport("testJob"));
Step step = new StepSupport("foo");
StepExecution stepExecution = new StepExecution(step, new JobExecution(job), null);
MockControl stepExecutionIncrementerControl = MockControl.createControl(DataFieldMaxValueIncrementer.class);
DataFieldMaxValueIncrementer stepExecutionIncrementer;
MockControl stepIncrementerControl = MockControl.createControl(DataFieldMaxValueIncrementer.class);
DataFieldMaxValueIncrementer stepIncrementer;
protected void setUp() throws Exception {
super.setUp();
stepExecutionDao = new JdbcStepExecutionDao();
stepExecutionIncrementer = (DataFieldMaxValueIncrementer)stepExecutionIncrementerControl.getMock();
stepIncrementer = (DataFieldMaxValueIncrementer)stepIncrementerControl.getMock();
stepExecutionDao.setJdbcTemplate(jdbcTemplate);
stepExecutionDao.setStepExecutionIncrementer(stepExecutionIncrementer);
stepExecution.setId(new Long(1));
stepExecution.incrementVersion();
}
public void testModifiedUpdateStepExecution(){
stepExecutionDao.setTablePrefix("FOO_");
stepExecutionDao.updateStepExecution(stepExecution);
assertTrue(jdbcTemplate.getSqlStatement().indexOf("FOO_STEP_EXECUTION") != -1);
}
public void testModifiedSaveStepExecution(){
stepExecutionDao.setTablePrefix("FOO_");
stepExecutionIncrementer.nextLongValue();
stepExecutionIncrementerControl.setReturnValue(1);
stepExecutionIncrementerControl.replay();
stepExecutionDao.saveStepExecution(stepExecution);
assertTrue(jdbcTemplate.getSqlStatement().indexOf("FOO_STEP_EXECUTION") != -1);
}
public void testDefaultSaveStepExecution(){
stepExecutionIncrementer.nextLongValue();
stepExecutionIncrementerControl.setReturnValue(1);
stepExecutionIncrementerControl.replay();
stepExecutionDao.saveStepExecution(stepExecution);
assertTrue(jdbcTemplate.getSqlStatement().indexOf("BATCH_STEP_EXECUTION") != -1);
}
public void testDefaultUpdateStepExecution(){
stepExecutionDao.updateStepExecution(stepExecution);
assertTrue(jdbcTemplate.getSqlStatement().indexOf("BATCH_STEP_EXECUTION") != -1);
}
private class MockJdbcTemplate extends JdbcTemplate {
private String sql;
public int update(String sql, Object[] args) throws DataAccessException {
this.sql = sql;
return 1;
}
public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
this.sql = sql;
return 1;
}
public List query(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {
this.sql = sql;
return null;
}
public String getSqlStatement() {
return sql;
}
}
}

View File

@@ -0,0 +1,41 @@
package org.springframework.batch.execution.repository.dao;
import java.util.List;
import java.util.Map;
import org.springframework.batch.repeat.ExitStatus;
public class JdbcStepDaoTests extends AbstractStepDaoTests {
private static final String LONG_STRING = JdbcJobDaoTests.LONG_STRING;
protected void onSetUpBeforeTransaction() throws Exception {
((JdbcStepExecutionDao) stepExecutionDao).setTablePrefix(AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX);
}
public void testTablePrefix() throws Exception {
// ((JdbcStepInstanceDao) stepInstanceDao).setTablePrefix("FOO_");
// ((JdbcStepExecutionDao) stepExecutionDao).setTablePrefix("FOO_");
// try {
// testCreateStep();
// fail("Expected DataAccessException");
// } catch (DataAccessException e) {
// // expected
// }
}
public void testUpdateStepExecutionWithLongExitCode() {
assertTrue(LONG_STRING.length()>250);
stepExecution.setExitStatus(ExitStatus.FINISHED.addExitDescription(LONG_STRING));
stepExecutionDao.updateStepExecution(stepExecution);
List executions = jdbcTemplate.queryForList(
"SELECT * FROM BATCH_STEP_EXECUTION where STEP_NAME=?",
new Object[] { step1.getName() });
assertEquals(1, executions.size());
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0))
.get("EXIT_MESSAGE"));
}
}

View File

@@ -0,0 +1,94 @@
package org.springframework.batch.execution.repository.dao;
import java.util.Date;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.execution.job.JobSupport;
public class MapJobExecutionDaoTests extends TestCase {
JobExecutionDao dao = new MapJobExecutionDao();
JobInstance jobInstance = new JobInstance(new Long(1), new JobParameters(), new JobSupport("execTestJob"));
JobExecution execution = new JobExecution(jobInstance);
protected void setUp() throws Exception {
MapJobExecutionDao.clear();
}
/**
* Save and find a job execution.
*/
public void testSaveAndFind() {
dao.saveJobExecution(execution);
List executions = dao.findJobExecutions(jobInstance);
assertTrue(executions.size() == 1);
assertEquals(execution, executions.get(0));
}
/**
* Saving sets id to the entity.
*/
public void testSaveAddsId() {
assertNull(execution.getId());
dao.saveJobExecution(execution);
assertNotNull(execution.getId());
}
/**
* Execution count increases by one with every save for the same job
* instance.
*/
public void testGetExecutionCount() {
JobExecution exec1 = new JobExecution(jobInstance);
JobExecution exec2 = new JobExecution(jobInstance);
dao.saveJobExecution(exec1);
assertEquals(1, dao.getJobExecutionCount(jobInstance));
dao.saveJobExecution(exec2);
assertEquals(2, dao.getJobExecutionCount(jobInstance));
}
/**
* Update and retrieve job execution - check attributes have changed as
* expected.
*/
public void testUpdateExecution() {
execution.setStatus(BatchStatus.STARTED);
dao.saveJobExecution(execution);
execution.setStatus(BatchStatus.COMPLETED);
dao.updateJobExecution(execution);
JobExecution updated = (JobExecution) dao.findJobExecutions(jobInstance).get(0);
assertEquals(execution, updated);
assertEquals(BatchStatus.COMPLETED, updated.getStatus());
}
/**
* Check the execution with most recent start time is returned
*/
public void testGetLastExecution() {
JobExecution exec1 = new JobExecution(jobInstance);
exec1.setStartTime(new Date(0));
JobExecution exec2 = new JobExecution(jobInstance);
exec2.setStartTime(new Date(1));
dao.saveJobExecution(exec1);
dao.saveJobExecution(exec2);
assertEquals(exec2, dao.getLastJobExecution(jobInstance));
}
}

View File

@@ -0,0 +1,56 @@
package org.springframework.batch.execution.repository.dao;
import junit.framework.TestCase;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.execution.job.JobSupport;
public class MapJobInstanceDaoTests extends TestCase {
private JobInstanceDao dao = new MapJobInstanceDao();
private Job fooJob = new JobSupport("foo");
private JobParameters fooParams = new JobParametersBuilder().addString("fooKey", "fooValue").toJobParameters();
protected void setUp() throws Exception {
MapJobInstanceDao.clear();
}
protected void tearDown() throws Exception {
MapJobInstanceDao.clear();
}
/**
* Create and retrieve a job instance.
*/
public void testCreateAndRetrieve() throws Exception {
JobInstance fooInstance = dao.createJobInstance(fooJob, fooParams);
assertNotNull(fooInstance.getId());
assertEquals(fooJob, fooInstance.getJob());
assertEquals(fooParams, fooInstance.getJobParameters());
JobInstance retrievedInstance = dao.getJobInstance(fooJob, fooParams);
assertEquals(fooInstance, retrievedInstance);
}
/**
* Trying to create instance twice for the same job+parameters causes error
*/
public void testCreateDuplicateInstance() {
dao.createJobInstance(fooJob, fooParams);
try {
dao.createJobInstance(fooJob, fooParams);
fail();
}
catch (IllegalStateException e) {
// expected
}
}
}

View File

@@ -0,0 +1,140 @@
/*
* 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.execution.repository.dao;
import java.util.HashMap;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.dao.OptimisticLockingFailureException;
public class MapStepExecutionDaoTests extends TestCase {
private StepExecutionDao dao = new MapStepExecutionDao();
private JobInstance jobInstance;
private JobExecution jobExecution;
private Step step;
private StepExecution stepExecution;
protected void setUp() throws Exception {
MapStepExecutionDao.clear();
jobInstance = new JobInstance(new Long(1), new JobParameters(), new JobSupport("testJob"));
jobExecution = new JobExecution(jobInstance, new Long(1));
step = new StepSupport("foo");
stepExecution = new StepExecution(step, jobExecution);
}
public void testSaveExecutionUpdatesId() throws Exception {
StepExecution execution = new StepExecution(step, new JobExecution(jobInstance, new Long(1)));
assertNull(execution.getId());
dao.saveStepExecution(execution);
assertNotNull(execution.getId());
}
public void testSaveAndFindExecution() {
stepExecution.setStatus(BatchStatus.STARTED);
dao.saveStepExecution(stepExecution);
StepExecution retrieved = dao.getStepExecution(jobExecution, step);
assertEquals(stepExecution, retrieved);
assertEquals(BatchStatus.STARTED, retrieved.getStatus());
}
public void testUpdateExecution() {
stepExecution.setStatus(BatchStatus.STARTED);
dao.saveStepExecution(stepExecution);
stepExecution.setStatus(BatchStatus.STOPPED);
dao.updateStepExecution(stepExecution);
StepExecution retrieved = dao.getStepExecution(jobExecution, step);
assertEquals(stepExecution, retrieved);
assertEquals(BatchStatus.STOPPED, retrieved.getStatus());
}
public void testSaveAndFindContext() {
ExecutionContext ctx = new ExecutionContext(new HashMap() {
{
put("key", "value");
}
});
stepExecution.setExecutionContext(ctx);
dao.saveOrUpdateExecutionContext(stepExecution);
ExecutionContext retrieved = dao.findExecutionContext(stepExecution);
assertEquals(ctx, retrieved);
}
public void testUpdateContext() {
ExecutionContext ctx = new ExecutionContext(new HashMap() {
{
put("key", "value");
}
});
stepExecution.setExecutionContext(ctx);
dao.saveOrUpdateExecutionContext(stepExecution);
ctx.putLong("longKey", 7);
dao.saveOrUpdateExecutionContext(stepExecution);
ExecutionContext retrieved = dao.findExecutionContext(stepExecution);
assertEquals(ctx, retrieved);
assertEquals(7, retrieved.getLong("longKey"));
}
public void testConcurrentModificationException() {
jobInstance = new JobInstance(new Long(1), new JobParameters(), new JobSupport("testJob"));
jobExecution = new JobExecution(jobInstance, new Long(1));
step = new StepSupport("foo");
StepExecution exec1 = new StepExecution(step, jobExecution);
dao.saveStepExecution(exec1);
StepExecution exec2 = new StepExecution(step, jobExecution);
exec2.setId(exec1.getId());
exec2.incrementVersion();
assertEquals(new Integer(0), exec1.getVersion());
assertEquals(exec1.getVersion(), exec2.getVersion());
dao.updateStepExecution(exec1);
assertEquals(new Integer(1), exec1.getVersion());
try {
dao.updateStepExecution(exec2);
fail();
}
catch (OptimisticLockingFailureException e) {
// expected
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.execution.repository.dao;
import org.springframework.batch.execution.repository.dao.NoSuchObjectException;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class NoSuchBatchDomainObjectExceptionTests extends TestCase {
public void testCreateException() throws Exception {
NoSuchObjectException e = new NoSuchObjectException("Foo");
assertEquals("Foo", e.getMessage());
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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.execution.resource;
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.StepSupport;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
/**
* Unit tests for {@link StepExecutionProxyResource}
*
* @author robert.kasanicky
* @author Lucas Ward
* @author Dave Syer
*/
public class StepExecutionProxyResourceTests extends TestCase {
/**
* Object under test
*/
private StepExecutionProxyResource resource = new StepExecutionProxyResource();
private char pathsep = File.separatorChar;
private String path = "data" + pathsep;
private JobInstance jobInstance;
private StepExecution stepExecution;
/**
* mock step context
*/
protected void setUp() throws Exception {
jobInstance = new JobInstance(new Long(0), new JobParameters(), new JobSupport("testJob"));
JobExecution jobExecution = new JobExecution(jobInstance);
Step step = new StepSupport("bar");
stepExecution = jobExecution.createStepExecution(step);
resource.beforeStep(stepExecution);
}
/**
* regular use with valid context and pattern provided
*/
public void testCreateFileName() throws Exception {
doTestPathName("bar.txt", path);
}
public void testNullFilePattern() throws Exception {
resource.setFilePattern(null);
try {
resource.beforeStep(stepExecution);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
}
}
public void testNonStandardFilePattern() throws Exception {
resource.setFilePattern("foo/data/%JOB_NAME%/" + "%STEP_NAME%-job");
resource.beforeStep(stepExecution);
doTestPathName("bar-job", "foo" + pathsep + "data" + pathsep);
}
public void testNonStandardFilePatternWithJobParameters() throws Exception {
resource.setFilePattern("foo/data/%JOB_NAME%/%job.key%-foo");
jobInstance = new JobInstance(new Long(0), new JobParametersBuilder().addString("job.key", "spam")
.toJobParameters(), new JobSupport("testJob"));
JobExecution jobExecution = new JobExecution(jobInstance);
Step step = new StepSupport("bar");
resource.beforeStep(jobExecution.createStepExecution(step));
doTestPathName("spam-foo", "foo" + pathsep + "data" + pathsep);
}
public void testResoureLoaderAware() throws Exception {
resource = new StepExecutionProxyResource();
resource.setResourceLoader(new DefaultResourceLoader() {
public Resource getResource(String location) {
return new ByteArrayResource("foo".getBytes());
}
});
resource.beforeStep(stepExecution);
assertTrue(resource.exists());
}
private void doTestPathName(String filename, String path) throws Exception, IOException {
String returnedPath = resource.getFile().getAbsolutePath();
String absolutePath = new File(path + jobInstance.getJobName() + pathsep + filename).getAbsolutePath();
assertEquals(absolutePath, returnedPath);
}
}

View File

@@ -0,0 +1,711 @@
/*
* 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.execution.step;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.UnexpectedJobExecutionException;
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.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.listener.StepListenerSupport;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.step.support.JobRepositorySupport;
import org.springframework.batch.execution.step.support.SimpleItemHandler;
import org.springframework.batch.execution.step.support.StepInterruptionPolicy;
import org.springframework.batch.item.AbstractItemReader;
import org.springframework.batch.item.AbstractItemWriter;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamSupport;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.MarkFailedException;
import org.springframework.batch.item.ResetFailedException;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.support.PropertiesConverter;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.DefaultTransactionStatus;
public class ItemOrientedStepTests extends TestCase {
ArrayList processed = new ArrayList();
private List list = new ArrayList();
ItemWriter itemWriter = new AbstractItemWriter() {
public void write(Object data) throws Exception {
processed.add((String) data);
}
};
private ItemOrientedStep itemOrientedStep;
private RepeatTemplate template;
private JobInstance jobInstance;
private ResourcelessTransactionManager transactionManager;
private ItemReader getReader(String[] args) {
return new ListItemReader(Arrays.asList(args));
}
private AbstractStep getStep(String[] strings) throws Exception {
ItemOrientedStep step = new ItemOrientedStep("stepName");
step.setItemHandler(new SimpleItemHandler(getReader(strings), itemWriter));
step.setJobRepository(new JobRepositorySupport());
step.setTransactionManager(transactionManager);
return step;
}
protected void setUp() throws Exception {
MapJobInstanceDao.clear();
MapStepExecutionDao.clear();
MapJobExecutionDao.clear();
transactionManager = new ResourcelessTransactionManager();
itemOrientedStep = (ItemOrientedStep) getStep(new String[] { "foo", "bar", "spam" });
template = new RepeatTemplate();
template.setCompletionPolicy(new SimpleCompletionPolicy(1));
itemOrientedStep.setStepOperations(template);
// Only process one item:
template = new RepeatTemplate();
template.setCompletionPolicy(new SimpleCompletionPolicy(1));
itemOrientedStep.setChunkOperations(template);
jobInstance = new JobInstance(new Long(0), new JobParameters(), new JobSupport("FOO"));
itemOrientedStep.setTransactionManager(transactionManager);
}
public void testStepExecutor() throws Exception {
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
itemOrientedStep.execute(stepExecution);
assertEquals(1, processed.size());
assertEquals(1, stepExecution.getTaskCount().intValue());
}
public void testChunkExecutor() throws Exception {
template = new RepeatTemplate();
// Only process one item:
template.setCompletionPolicy(new SimpleCompletionPolicy(1));
itemOrientedStep.setChunkOperations(template);
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
StepContribution contribution = stepExecution.createStepContribution();
itemOrientedStep.processChunk(contribution);
assertEquals(1, processed.size());
assertEquals(0, stepExecution.getTaskCount().intValue());
assertEquals(1, contribution.getTaskCount());
}
public void testRepository() throws Exception {
SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
new MapStepExecutionDao());
itemOrientedStep.setJobRepository(repository);
JobExecution jobExecution = repository.createJobExecution(jobInstance.getJob(), jobInstance.getJobParameters());
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.execute(stepExecution);
assertEquals(1, processed.size());
}
public void testIncrementRollbackCount() {
ItemReader itemReader = new AbstractItemReader() {
public Object read() throws Exception {
int counter = 0;
counter++;
if (counter == 1) {
throw new RuntimeException();
}
return ExitStatus.CONTINUABLE;
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
try {
itemOrientedStep.execute(stepExecution);
} catch (Exception ex) {
assertEquals(stepExecution.getRollbackCount(), new Integer(1));
}
}
public void testExitCodeDefaultClassification() throws Exception {
ItemReader itemReader = new AbstractItemReader() {
public Object read() throws Exception {
int counter = 0;
counter++;
if (counter == 1) {
throw new RuntimeException();
}
return ExitStatus.CONTINUABLE;
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
try {
itemOrientedStep.execute(stepExecution);
} catch (Exception ex) {
ExitStatus status = stepExecution.getExitStatus();
assertFalse(status.isContinuable());
}
}
/*
* make sure a job that has never been executed before, but does have saveExecutionAttributes = true, doesn't have
* restoreFrom called on it.
*/
public void testNonRestartedJob() throws Exception {
MockRestartableItemReader tasklet = new MockRestartableItemReader();
itemOrientedStep.setItemHandler(new SimpleItemHandler(tasklet, itemWriter));
itemOrientedStep.registerStream(tasklet);
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
itemOrientedStep.execute(stepExecution);
assertFalse(tasklet.isRestoreFromCalled());
assertTrue(tasklet.isGetExecutionAttributesCalled());
}
public void testSuccessfulExecutionWithExecutionContext() throws Exception {
final JobExecution jobExecution = new JobExecution(jobInstance);
final StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.setJobRepository(new JobRepositorySupport() {
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
list.add(stepExecution);
}
});
itemOrientedStep.execute(stepExecution);
assertEquals(1, list.size());
}
public void testSuccessfulExecutionWithFailureOnSaveOfExecutionContext() throws Exception {
final JobExecution jobExecution = new JobExecution(jobInstance);
final StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.setJobRepository(new JobRepositorySupport() {
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
throw new RuntimeException("foo");
}
});
try {
itemOrientedStep.execute(stepExecution);
fail("Expected BatchCriticalException");
} catch (UnexpectedJobExecutionException e) {
assertEquals("foo", e.getCause().getMessage());
}
assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus());
}
/*
* make sure a job that has been executed before, and is therefore being restarted, is restored.
*/
// public void testRestartedJob() throws Exception {
// String step = "stepName";
// // step.setStepExecutionCount(1);
// MockRestartableItemReader tasklet = new MockRestartableItemReader();
// stepExecutor.setItemReader(tasklet);
// stepConfiguration.setSaveExecutionContext(true);
// JobExecution jobExecution = new JobExecution(jobInstance);
// StepExecution stepExecution = new StepExecution(step, jobExecution);
//
// stepExecution
// .setExecutionContext(new
// ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// // step.setLastExecution(stepExecution);
// stepExecutor.execute(stepExecution);
//
// assertTrue(tasklet.isRestoreFromCalled());
// assertTrue(tasklet.isRestoreFromCalledWithSomeContext());
// assertTrue(tasklet.isGetExecutionAttributesCalled());
// }
/*
* Test that a job that is being restarted, but has saveExecutionAttributes set to false, doesn't have restore or
* getExecutionAttributes called on it.
*/
public void testNoSaveExecutionAttributesRestartableJob() {
MockRestartableItemReader tasklet = new MockRestartableItemReader();
itemOrientedStep.setItemHandler(new SimpleItemHandler(tasklet, itemWriter));
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
try {
itemOrientedStep.execute(stepExecution);
} catch (Throwable t) {
fail();
}
assertFalse(tasklet.isRestoreFromCalled());
}
/*
* Even though the job is restarted, and saveExecutionAttributes is true, nothing will be restored because the
* Tasklet does not implement Restartable.
*/
public void testRestartJobOnNonRestartableTasklet() throws Exception {
itemOrientedStep.setItemHandler(new SimpleItemHandler(new AbstractItemReader() {
public Object read() throws Exception {
return "foo";
}
}, itemWriter));
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.execute(stepExecution);
}
public void testStreamManager() throws Exception {
MockRestartableItemReader reader = new MockRestartableItemReader() {
public Object read() throws Exception {
return "foo";
}
public void update(ExecutionContext executionContext) {
// TODO Auto-generated method stub
executionContext.putString("foo", "bar");
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(reader, itemWriter));
itemOrientedStep.registerStream(reader);
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
assertEquals(false, stepExecution.getExecutionContext().containsKey("foo"));
itemOrientedStep.execute(stepExecution);
// At least once in that process the statistics service was asked for
// statistics...
assertEquals("bar", stepExecution.getExecutionContext().getString("foo"));
}
public void testDirectlyInjectedItemStream() throws Exception {
itemOrientedStep.setStreams(new ItemStream[] { new ItemStreamSupport() {
public void update(ExecutionContext executionContext) {
executionContext.putString("foo", "bar");
}
} });
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
assertEquals(false, stepExecution.getExecutionContext().containsKey("foo"));
itemOrientedStep.execute(stepExecution);
assertEquals("bar", stepExecution.getExecutionContext().getString("foo"));
}
public void testDirectlyInjectedListener() throws Exception {
itemOrientedStep.registerStepListener(new StepListenerSupport() {
public void beforeStep(StepExecution stepExecution) {
list.add("foo");
}
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("bar");
return null;
}
});
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.execute(stepExecution);
assertEquals(2, list.size());
}
public void testListenerCalledBeforeStreamOpened() throws Exception {
MockRestartableItemReader reader = new MockRestartableItemReader() {
public void beforeStep(StepExecution stepExecution) {
list.add("foo");
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
assertEquals(1, list.size());
}
};
itemOrientedStep.setStreams(new ItemStream[] { reader });
itemOrientedStep.registerStepListener(reader);
StepExecution stepExecution = new StepExecution(itemOrientedStep, new JobExecution(jobInstance));
itemOrientedStep.execute(stepExecution);
assertEquals(1, list.size());
}
public void testAfterStep() throws Exception {
final ExitStatus customStatus = new ExitStatus(false, "custom code");
itemOrientedStep.setStepListeners(new StepListener[] { new StepListenerSupport() {
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("afterStepCalled");
return customStatus;
}
} });
RepeatTemplate stepTemplate = new RepeatTemplate();
stepTemplate.setCompletionPolicy(new SimpleCompletionPolicy(5));
itemOrientedStep.setStepOperations(stepTemplate);
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
itemOrientedStep.execute(stepExecution);
assertEquals(1, list.size());
ExitStatus returnedStatus = stepExecution.getExitStatus();
assertEquals(customStatus.getExitCode(), returnedStatus.getExitCode());
assertEquals(customStatus.getExitDescription(), returnedStatus.getExitDescription());
}
public void testDirectlyInjectedListenerOnError() throws Exception {
itemOrientedStep.registerStepListener(new StepListenerSupport() {
public ExitStatus onErrorInStep(StepExecution stepExecution, Throwable e) {
list.add(e);
return null;
}
});
itemOrientedStep.setItemHandler(new SimpleItemHandler(new MockRestartableItemReader() {
public Object read() throws Exception {
throw new RuntimeException("FOO");
}
}, itemWriter));
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected RuntimeException");
} catch (RuntimeException e) {
assertEquals("FOO", e.getMessage());
}
assertEquals(1, list.size());
}
public void testDirectlyInjectedStreamWhichIsAlsoReader() throws Exception {
MockRestartableItemReader reader = new MockRestartableItemReader() {
public Object read() throws Exception {
return "foo";
}
public void update(ExecutionContext executionContext) {
// TODO Auto-generated method stub
executionContext.putString("foo", "bar");
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(reader, itemWriter));
itemOrientedStep.setStreams(new ItemStream[] { reader });
JobExecution jobExecution = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecution);
assertEquals(false, stepExecution.getExecutionContext().containsKey("foo"));
itemOrientedStep.execute(stepExecution);
// At least once in that process the statistics service was asked for
// statistics...
assertEquals("bar", stepExecution.getExecutionContext().getString("foo"));
}
public void testStatusForInterruptedException() {
StepInterruptionPolicy interruptionPolicy = new StepInterruptionPolicy() {
public void checkInterrupted(RepeatContext context) throws JobInterruptedException {
throw new JobInterruptedException("");
}
};
itemOrientedStep.setInterruptionPolicy(interruptionPolicy);
ItemReader itemReader = new AbstractItemReader() {
public Object read() throws Exception {
int counter = 0;
counter++;
if (counter == 1) {
throw new RuntimeException();
}
return ExitStatus.CONTINUABLE;
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// step.setLastExecution(stepExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected StepInterruptedException");
} catch (JobInterruptedException ex) {
assertEquals(BatchStatus.STOPPED, stepExecution.getStatus());
String msg = stepExecution.getExitStatus().getExitDescription();
assertTrue("Message does not contain JobInterruptedException: " + msg, msg
.contains("JobInterruptedException"));
}
}
public void testStatusForNormalFailure() throws Exception {
ItemReader itemReader = new AbstractItemReader() {
public Object read() throws Exception {
// Trigger a rollback
throw new RuntimeException("Foo");
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// step.setLastExecution(stepExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected RuntimeException");
} catch (RuntimeException ex) {
assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
// The original rollback was caused by this one:
assertEquals("Foo", ex.getMessage());
}
}
public void testStatusForResetFailedException() throws Exception {
ItemReader itemReader = new AbstractItemReader() {
public Object read() throws Exception {
// Trigger a rollback
throw new RuntimeException("Foo");
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
itemOrientedStep.setTransactionManager(new ResourcelessTransactionManager() {
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
// Simulate failure on rollback when stream resets
throw new ResetFailedException("Bar");
}
});
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// step.setLastExecution(stepExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected BatchCriticalException");
} catch (UnexpectedJobExecutionException ex) {
assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus());
String msg = stepExecution.getExitStatus().getExitDescription();
assertTrue("Message does not contain ResetFailedException: " + msg, msg.contains("ResetFailedException"));
// The original rollback was caused by this one:
assertEquals("Bar", ex.getCause().getMessage());
}
}
public void testStatusForCommitFailedException() throws Exception {
itemOrientedStep.setTransactionManager(new ResourcelessTransactionManager() {
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
// Simulate failure on rollback when stream resets
throw new RuntimeException("Bar");
}
});
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// step.setLastExecution(stepExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected BatchCriticalException");
} catch (UnexpectedJobExecutionException ex) {
assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus());
String msg = stepExecution.getExitStatus().getExitDescription();
assertEquals("", msg);
msg = ex.getMessage();
assertTrue("Message does not contain 'saving': " + msg, msg.contains("saving"));
// The original rollback was caused by this one:
assertEquals("Bar", ex.getCause().getMessage());
}
}
public void testStatusForFinalUpdateFailedException() throws Exception {
itemOrientedStep.setJobRepository(new JobRepositorySupport() {
public void saveOrUpdate(StepExecution stepExecution) {
if (stepExecution.getEndTime() != null) {
throw new RuntimeException("Bar");
}
super.saveOrUpdate(stepExecution);
}
});
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected RuntimeException");
} catch (RuntimeException ex) {
// The job actually completeed, but teh streams couldn't be closed.
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
String msg = stepExecution.getExitStatus().getExitDescription();
assertEquals("", msg);
msg = ex.getMessage();
assertTrue("Message does not contain 'final': " + msg, msg.contains("final"));
// The original rollback was caused by this one:
assertEquals("Bar", ex.getCause().getMessage());
}
}
public void testStatusForCloseFailedException() throws Exception {
MockRestartableItemReader itemReader = new MockRestartableItemReader() {
public void close(ExecutionContext executionContext) throws ItemStreamException {
super.close(executionContext);
// Simulate failure on rollback when stream resets
throw new RuntimeException("Bar");
}
};
itemOrientedStep.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
itemOrientedStep.registerStream(itemReader);
JobExecution jobExecutionContext = new JobExecution(jobInstance);
StepExecution stepExecution = new StepExecution(itemOrientedStep, jobExecutionContext);
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
// step.setLastExecution(stepExecution);
try {
itemOrientedStep.execute(stepExecution);
fail("Expected InfrastructureException");
} catch (UnexpectedJobExecutionException ex) {
// The job actually completeed, but the streams couldn't be closed.
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
String msg = stepExecution.getExitStatus().getExitDescription();
assertEquals("", msg);
msg = ex.getMessage();
assertTrue("Message does not contain 'close': " + msg, msg.contains("close"));
// The original rollback was caused by this one:
assertEquals("Bar", ex.getCause().getMessage());
}
}
private class MockRestartableItemReader extends ItemStreamSupport implements ItemReader, StepListener {
private boolean getExecutionAttributesCalled = false;
private boolean restoreFromCalled = false;
private boolean restoreFromCalledWithSomeContext = false;
public Object read() throws Exception {
return "item";
}
public boolean isRestoreFromCalledWithSomeContext() {
return restoreFromCalledWithSomeContext;
}
public void update(ExecutionContext executionContext) {
getExecutionAttributesCalled = true;
executionContext.putString("spam", "bucket");
}
public boolean isGetExecutionAttributesCalled() {
return getExecutionAttributesCalled;
}
public boolean isRestoreFromCalled() {
return restoreFromCalled;
}
public void mark() throws MarkFailedException {
}
public void reset() throws ResetFailedException {
}
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
public void beforeStep(StepExecution stepExecution) {
}
public ExitStatus onErrorInStep(StepExecution stepExecution, Throwable e) {
return null;
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.execution.step;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.beans.factory.BeanNameAware;
/**
* Basic no-op support implementation for use as base class for {@link Step}. Implements {@link BeanNameAware} so that
* if no name is provided explicitly it will be inferred from the bean definition in Spring configuration.
*
* @author Dave Syer
*
*/
public class StepSupport implements Step, BeanNameAware {
private String name;
private int startLimit = Integer.MAX_VALUE;
private boolean allowStartIfComplete;
/**
* Default constructor for {@link StepSupport}.
*/
public StepSupport() {
super();
}
/**
* @param string
*/
public StepSupport(String string) {
super();
this.name = string;
}
public String getName() {
return this.name;
}
/**
* Set the name property if it is not already set. Because of the order of the callbacks in a Spring container the
* name property will be set first if it is present. Care is needed with bean definition inheritance - if a parent
* bean has a name, then its children need an explicit name as well, otherwise they will not be unique.
*
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
*/
public void setBeanName(String name) {
if (this.name == null) {
this.name = name;
}
}
/**
* Set the name property. Always overrides the default value if this object is a Spring bean.
*
* @see #setBeanName(java.lang.String)
*/
public void setName(String name) {
this.name = name;
}
public int getStartLimit() {
return this.startLimit;
}
/**
* Public setter for the startLimit.
*
* @param startLimit the startLimit to set
*/
public void setStartLimit(int startLimit) {
this.startLimit = startLimit;
}
public boolean isAllowStartIfComplete() {
return this.allowStartIfComplete;
}
/**
* Public setter for the shouldAllowStartIfComplete.
*
* @param allowStartIfComplete the shouldAllowStartIfComplete to set
*/
public void setAllowStartIfComplete(boolean allowStartIfComplete) {
this.allowStartIfComplete = allowStartIfComplete;
}
/**
* Not supported but provided so that tests can easily create a step.
*
* @throws UnsupportedOperationException always
*
* @see org.springframework.batch.core.Step#execute(org.springframework.batch.core.StepExecution)
*/
public void execute(StepExecution stepExecution) throws JobInterruptedException, UnexpectedJobExecutionException {
throw new UnsupportedOperationException(
"Cannot process a StepExecution. Use a smarter subclass of StepSupport.");
}
}

View File

@@ -0,0 +1,179 @@
package org.springframework.batch.execution.step;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.UnexpectedJobExecutionException;
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.StepExecution;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.listener.StepListenerSupport;
import org.springframework.batch.core.tasklet.Tasklet;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.step.support.JobRepositorySupport;
import org.springframework.batch.repeat.ExitStatus;
public class TaskletStepTests extends TestCase {
private StepExecution stepExecution;
private List list = new ArrayList();
protected void setUp() throws Exception {
stepExecution = new StepExecution(new StepSupport("stepName"), new JobExecution(new JobInstance(new Long(0L),
new JobParameters(), new JobSupport("testJob")), new Long(12)));
}
public void testTaskletMandatory() throws Exception {
TaskletStep step = new TaskletStep();
step.setJobRepository(new JobRepositorySupport());
try {
step.afterPropertiesSet();
}
catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain 'tasklet': " + message, message.toLowerCase().contains("tasklet"));
}
}
public void testRepositoryMandatory() throws Exception {
TaskletStep step = new TaskletStep();
try {
step.afterPropertiesSet();
}
catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Message should contain 'tasklet': " + message, message.toLowerCase().contains("tasklet"));
}
}
public void testSuccessfulExecution() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(false, false), new JobRepositorySupport());
step.execute(stepExecution);
assertNotNull(stepExecution.getStartTime());
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertNotNull(stepExecution.getEndTime());
}
public void testSuccessfulExecutionWithStepContext() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(false, false, true), new JobRepositorySupport());
step.afterPropertiesSet();
step.execute(stepExecution);
assertNotNull(stepExecution.getStartTime());
assertEquals(ExitStatus.FINISHED, stepExecution.getExitStatus());
assertNotNull(stepExecution.getEndTime());
}
public void testSuccessfulExecutionWithExecutionContext() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(false, false), new JobRepositorySupport() {
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
list.add(stepExecution);
}
});
step.execute(stepExecution);
assertEquals(1, list.size());
}
public void testSuccessfulExecutionWithFailureOnSaveOfExecutionContext() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(false, false, true), new JobRepositorySupport() {
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
throw new RuntimeException("foo");
}
});
step.afterPropertiesSet();
try {
step.execute(stepExecution);
fail("Expected BatchCriticalException");
}
catch (UnexpectedJobExecutionException e) {
assertEquals("foo", e.getCause().getMessage());
}
assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus());
}
public void testFailureExecution() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(true, false), new JobRepositorySupport());
step.execute(stepExecution);
assertNotNull(stepExecution.getStartTime());
assertEquals(ExitStatus.FAILED, stepExecution.getExitStatus());
assertNotNull(stepExecution.getEndTime());
}
public void testSuccessfulExecutionWithListener() throws Exception {
TaskletStep step = new TaskletStep(new StubTasklet(false, false), new JobRepositorySupport());
step.setStepListeners(new StepListener[] { new StepListenerSupport() {
public void beforeStep(StepExecution context) {
list.add("open");
}
public ExitStatus afterStep(StepExecution stepExecution) {
list.add("close");
return ExitStatus.CONTINUABLE;
}
} });
step.execute(stepExecution);
assertEquals(2, list.size());
}
public void testExceptionExecution() throws JobInterruptedException, UnexpectedJobExecutionException {
TaskletStep step = new TaskletStep(new StubTasklet(false, true), new JobRepositorySupport());
try {
step.execute(stepExecution);
fail();
}
catch (RuntimeException e) {
assertNotNull(stepExecution.getStartTime());
assertEquals(ExitStatus.FAILED, stepExecution.getExitStatus());
assertNotNull(stepExecution.getEndTime());
}
}
private class StubTasklet extends StepListenerSupport implements Tasklet {
private final boolean exitFailure;
private final boolean throwException;
private final boolean assertStepContext;
private StepExecution stepExecution;
public StubTasklet(boolean exitFailure, boolean throwException) {
this(exitFailure, throwException, false);
}
public StubTasklet(boolean exitFailure, boolean throwException, boolean assertStepContext) {
this.exitFailure = exitFailure;
this.throwException = throwException;
this.assertStepContext = assertStepContext;
}
public ExitStatus execute() throws Exception {
if (throwException) {
throw new Exception();
}
if (exitFailure) {
return ExitStatus.FAILED;
}
if (assertStepContext) {
assertNotNull(this.stepExecution);
}
return ExitStatus.FINISHED;
}
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}
}

View File

@@ -0,0 +1,189 @@
/*
* 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.execution.step.support;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchListener;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.listener.ItemListenerSupport;
import org.springframework.batch.execution.job.SimpleJob;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.step.AbstractStep;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.AbstractItemWriter;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.exception.ExceptionHandler;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
public class DefaultStepFactoryBeanTests extends TestCase {
private List recovered = new ArrayList();
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
new MapStepExecutionDao());
private List processed = new ArrayList();
private ItemWriter processor = new AbstractItemWriter() {
public void write(Object data) throws Exception {
processed.add((String) data);
}
};
private ItemReader provider;
private SimpleJob job = new SimpleJob();;
protected void setUp() throws Exception {
super.setUp();
job.setJobRepository(repository);
MapJobInstanceDao.clear();
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
}
private DefaultStepFactoryBean getStep(String arg) throws Exception {
return getStep(new String[] { arg });
}
private DefaultStepFactoryBean getStep(String arg0, String arg1) throws Exception {
return getStep(new String[] { arg0, arg1 });
}
private DefaultStepFactoryBean getStep(String[] args) throws Exception {
DefaultStepFactoryBean factory = new DefaultStepFactoryBean();
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(args));
provider = new ListItemReader(items);
factory.setItemReader(provider);
factory.setItemWriter(processor);
factory.setJobRepository(repository);
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.setBeanName("stepName");
return factory;
}
public void testSimpleJob() throws Exception {
job.setSteps(new ArrayList());
AbstractStep step = (AbstractStep) getStep("foo", "bar").getObject();
step.setName("step1");
job.addStep(step);
step = (AbstractStep) getStep("spam").getObject();
step.setName("step2");
job.addStep(step);
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
job.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(3, processed.size());
assertTrue(processed.contains("foo"));
}
public void testSimpleJobWithItemListeners() throws Exception {
final List throwables = new ArrayList();
RepeatTemplate chunkOperations = new RepeatTemplate();
// Always handle the exception a check it is the right one...
chunkOperations.setExceptionHandler(new ExceptionHandler() {
public void handleException(RepeatContext context, Throwable throwable) throws RuntimeException {
throwables.add(throwable);
assertEquals("Error!", throwable.getMessage());
}
});
/*
* Each message fails once and the chunk (size=1) "rolls back"; then it
* is recovered ("skipped") on the second attempt (see retry policy
* definition above)...
*/
DefaultStepFactoryBean factory = getStep(new String[] { "foo", "bar", "spam" });
factory.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Error!");
}
});
factory.setListeners(new BatchListener[] { new ItemListenerSupport() {
public void onReadError(Exception ex) {
recovered.add(ex);
}
public void onWriteError(Exception ex, Object item) {
recovered.add(ex);
}
} });
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
step.setChunkOperations(chunkOperations);
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
job.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(0, processed.size());
// provider should be exhausted
assertEquals(null, provider.read());
assertEquals(3, recovered.size());
}
public void testExceptionTerminates() throws Exception {
DefaultStepFactoryBean factory = getStep(new String[] { "foo", "bar", "spam" });
factory.setBeanName("exceptionStep");
factory.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Foo");
}
});
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
try {
job.execute(jobExecution);
fail("Expected RuntimeException");
}
catch (RuntimeException e) {
assertEquals("Foo", e.getMessage());
// expected
}
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.execution.step.support;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobRepository;
/**
* @author Dave Syer
*
*/
public class JobRepositorySupport implements JobRepository {
/* (non-Javadoc)
* @see org.springframework.batch.container.common.repository.JobRepository#findOrCreateJob(org.springframework.batch.container.common.domain.JobConfiguration)
*/
public JobExecution createJobExecution(Job jobConfiguration, JobParameters jobParameters) {
return null;
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.repository.JobRepository#saveOrUpdate(org.springframework.batch.container.common.domain.JobExecution)
*/
public void saveOrUpdate(JobExecution jobExecution) {
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.repository.JobRepository#saveOrUpdate(org.springframework.batch.container.common.domain.StepExecution)
*/
public void saveOrUpdate(StepExecution stepExecution) {
}
/* (non-Javadoc)
* @see org.springframework.batch.core.repository.JobRepository#saveOrUpdateExecutionContext(org.springframework.batch.core.domain.StepExecution)
*/
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.repository.JobRepository#update(org.springframework.batch.container.common.domain.Job)
*/
public void update(JobInstance job) {
}
public StepExecution getLastStepExecution(JobInstance jobInstance, Step step) {
// TODO Auto-generated method stub
return null;
}
public int getStepExecutionCount(JobInstance jobInstance, Step step) {
// TODO Auto-generated method stub
return 0;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.execution.step.support;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.MarkFailedException;
import org.springframework.batch.item.ResetFailedException;
public class MockItemReader implements ItemReader {
private final int returnItemCount;
private int returnedItemCount;
private boolean fail = false;
public MockItemReader() {
this(-1);
}
public MockItemReader(int returnItemCount) {
this.returnItemCount = returnItemCount;
}
public void setFail(boolean fail) {
this.fail = fail;
}
public void close() {
}
public Object read() {
if(fail) {
fail = false;
throw new RuntimeException();
}
if (returnItemCount < 0 || returnedItemCount < returnItemCount) {
return String.valueOf(returnedItemCount++);
}
return null;
}
public Object getKey(Object item) {
// TODO Auto-generated method stub
return null;
}
public void mark() throws MarkFailedException {
}
public void reset() throws ResetFailedException {
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.execution.step.support;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.launch.EmptyItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.RepeatCallback;
import org.springframework.batch.repeat.RepeatOperations;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
/**
* @author Dave Syer
*
*/
public class RepeatOperationsStepFactoryBeanTests extends TestCase {
private RepeatOperationsStepFactoryBean factory = new RepeatOperationsStepFactoryBean();
private List list;
private JobExecution jobExecution = new JobExecution(new JobInstance(new Long(0L), new JobParameters(),
new JobSupport("job")));
protected void setUp() throws Exception {
factory.setItemReader(new ListItemReader(new ArrayList()));
factory.setItemWriter(new EmptyItemWriter());
factory.setJobRepository(new JobRepositorySupport());
factory.setTransactionManager(new ResourcelessTransactionManager());
}
public void testType() throws Exception {
assertEquals(Step.class, factory.getObjectType());
}
public void testDefaultValue() throws Exception {
assertTrue(factory.getObject() instanceof Step);
}
public void testStepOperationsWithoutChunkListener() throws Exception {
factory.setItemReader(new ListItemReader(new ArrayList()));
factory.setItemWriter(new EmptyItemWriter());
factory.setJobRepository(new JobRepositorySupport());
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.setStepOperations(new RepeatOperations() {
public ExitStatus iterate(RepeatCallback callback) {
list = new ArrayList();
list.add("foo");
return ExitStatus.FINISHED;
}
});
Step step = (Step) factory.getObject();
step.execute(new StepExecution(step, jobExecution));
assertEquals(1, list.size());
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.execution.step.support;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.repository.NoSuchJobException;
import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier;
import org.springframework.batch.execution.launch.support.ExitCodeMapper;
import org.springframework.batch.execution.step.support.SimpleExitStatusExceptionClassifier;
import org.springframework.batch.repeat.ExitStatus;
import junit.framework.TestCase;
/**
* @author Lucas Ward
*
*/
public class SimpleExitStatusExceptionClassifierTests extends TestCase {
NullPointerException exception;
SimpleExitStatusExceptionClassifier classifier = new SimpleExitStatusExceptionClassifier();
protected void setUp() throws Exception {
super.setUp();
exception = new NullPointerException();
}
public void testClassifyForExitCode() {
ExitStatus exitStatus = classifier.classifyForExitCode(exception);
assertEquals(exitStatus.getExitCode(), "FATAL_EXCEPTION");
String description = exitStatus.getExitDescription();
assertTrue("Description does not contain NullPointerException: "+description, description.indexOf("java.lang.NullPointerException")>=0);
}
public void testClassify() {
ExitStatus exitStatus = (ExitStatus)classifier.classify(exception);
assertEquals(exitStatus.getExitCode(), "FATAL_EXCEPTION");
String description = exitStatus.getExitDescription();
assertTrue("Description does not contain NullPointerException: "+description, description.indexOf("java.lang.NullPointerException")>=0);
}
public void testGetDefault() {
ExitStatus exitStatus = (ExitStatus)classifier.getDefault();
assertEquals(exitStatus.getExitCode(), "FATAL_EXCEPTION");
assertEquals(exitStatus.getExitDescription(), "");
}
/*
* Attempting to classify a null throwable should lead to a blank description, not a
* null pointer exception.
*/
public void testClassifyNullThrowable(){
ExitStatus exitStatus = (ExitStatus)classifier.classify(null);
assertEquals(exitStatus.getExitCode(), "FATAL_EXCEPTION");
assertEquals(exitStatus.getExitDescription(), "");
}
public void testClassifyInterruptedException(){
ExitStatus exitStatus = (ExitStatus)classifier.classifyForExitCode(new JobInterruptedException(""));
assertEquals(exitStatus.getExitCode(), ExitStatusExceptionClassifier.JOB_INTERRUPTED);
assertEquals(exitStatus.getExitDescription(),
JobInterruptedException.class.getName());
}
/**
* a NoSuchJobException should lead to the related constant
*/
public void testClassifyNoSuchJobException() {
ExitStatus exitStatus = (ExitStatus)classifier.classifyForExitCode(new NoSuchJobException(""));
assertEquals(exitStatus.getExitCode(), ExitCodeMapper.NO_SUCH_JOB);
assertEquals(exitStatus.getExitDescription(), "");
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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.execution.step.support;
import junit.framework.TestCase;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.context.RepeatContextSupport;
import org.springframework.batch.repeat.exception.SimpleLimitExceptionHandler;
import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.batch.retry.RetryContext;
import org.springframework.batch.retry.RetryPolicy;
import org.springframework.batch.retry.policy.AlwaysRetryPolicy;
import org.springframework.batch.retry.policy.NeverRetryPolicy;
/**
* @author Dave Syer
*
*/
public class SimpleRetryExceptionHandlerTests extends TestCase {
private RepeatContext context = new RepeatContextSupport(new RepeatContextSupport(null));
/*
* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
RepeatSynchronizationManager.register(context);
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception {
RepeatSynchronizationManager.clear();
}
/**
* Test method for
* {@link org.springframework.batch.execution.step.support.SimpleRetryExceptionHandler#handleException(org.springframework.batch.repeat.RepeatContext, java.lang.Throwable)}.
*/
public void testRethrowWhenRetryExhausted() {
RetryPolicy retryPolicy = new NeverRetryPolicy();
RuntimeException ex = new RuntimeException("foo");
SimpleRetryExceptionHandler handler = getHandlerAfterRetry(retryPolicy, ex);
// Then pretend to handle the exception in the parent context...
try {
handler.handleException(context.getParent(), ex);
fail("Expected RuntimeException");
}
catch (RuntimeException e) {
assertEquals(ex, e);
}
assertEquals(0, context.attributeNames().length);
// One for the retry exhausted flag and one for the counter in the delegate exception handler
assertEquals(2, context.getParent().attributeNames().length);
}
/**
* Test method for
* {@link org.springframework.batch.execution.step.support.SimpleRetryExceptionHandler#handleException(org.springframework.batch.repeat.RepeatContext, java.lang.Throwable)}.
*/
public void testNoRethrowWhenRetryNotExhausted() {
RetryPolicy retryPolicy = new AlwaysRetryPolicy();
RuntimeException ex = new RuntimeException("foo");
SimpleRetryExceptionHandler handler = getHandlerAfterRetry(retryPolicy, ex);
// Then pretend to handle the exception in the parent context...
handler.handleException(context.getParent(), ex);
assertEquals(0, context.attributeNames().length);
assertEquals(0, context.getParent().attributeNames().length);
}
/**
* @param retryPolicy
* @param ex
* @return
*/
private SimpleRetryExceptionHandler getHandlerAfterRetry(RetryPolicy retryPolicy, RuntimeException ex) {
// Always rethrow if the retry is exhausted
SimpleRetryExceptionHandler handler = new SimpleRetryExceptionHandler(retryPolicy, new SimpleLimitExceptionHandler(0));
// Simulate a failed retry...
RetryContext retryContext = retryPolicy.open(null);
retryPolicy.registerThrowable(retryContext, ex);
handler.close(retryContext, null, ex);
return handler;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2006-2008 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.execution.step.support;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.item.file.FlatFileParseException;
/**
* @author Lucas Ward
*
*/
public class SkipLimitReadFailurePolicyTests extends TestCase {
private LimitCheckingItemSkipPolicy failurePolicy;
protected void setUp() throws Exception {
super.setUp();
List skippableExceptions = new ArrayList();
skippableExceptions.add(FlatFileParseException.class);
failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
public void testLimitExceed(){
try{
failurePolicy.shouldSkip(new FlatFileParseException("", ""), 2);
fail();
}
catch(SkipLimitExceededException ex){
//expected
}
}
public void testNonSkippableException(){
assertFalse(failurePolicy.shouldSkip(new FileNotFoundException(), 2));
}
public void testSkip(){
assertTrue(failurePolicy.shouldSkip(new FlatFileParseException("",""), 0));
}
}

View File

@@ -0,0 +1,128 @@
/*
* 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.execution.step.support;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.AbstractItemWriter;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Dave Syer
*
*/
public class StatefulRetryStepFactoryBeanTests extends TestCase {
private StatefulRetryStepFactoryBean factory = new StatefulRetryStepFactoryBean();
private List recovered = new ArrayList();
private List processed = new ArrayList();
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
new MapStepExecutionDao());
JobExecution jobExecution;
private ItemWriter processor = new AbstractItemWriter() {
public void write(Object data) throws Exception {
processed.add((String) data);
}
};
/*
* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
MapJobInstanceDao.clear();
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
factory.setBeanName("step");
factory.setItemReader(new ListItemReader(new ArrayList()));
factory.setItemWriter(processor);
factory.setJobRepository(repository);
factory.setTransactionManager(new ResourcelessTransactionManager());
JobSupport job = new JobSupport("jobName");
job.setRestartable(true);
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique").toJobParameters();
jobExecution = repository.createJobExecution(job, jobParameters);
jobExecution.setEndTime(new Date());
}
public void testType() throws Exception {
assertEquals(Step.class, factory.getObjectType());
}
public void testDefaultValue() throws Exception {
assertTrue(factory.getObject() instanceof Step);
}
public void testRecovery() throws Exception {
factory.setItemRecoverer(new ItemRecoverer() {
public boolean recover(Object item, Throwable cause) {
recovered.add(item);
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
return true;
}
});
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
ItemReader provider = new ListItemReader(items) {
int count = 0;
public Object read() {
count++;
if (count == 2) {
throw new RuntimeException("Temporary error - retry for success.");
}
return super.read();
}
};
factory.setItemReader(provider);
factory.setRetryLimit(10);
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
step.execute(new StepExecution(step, jobExecution));
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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.execution.step.support;
import junit.framework.TestCase;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.AbstractItemReader;
import org.springframework.batch.item.AbstractItemWriter;
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
public class StepExecutorInterruptionTests extends TestCase {
private ItemOrientedStep step;
private JobExecution jobExecution;
private AbstractItemWriter itemWriter;
private StepExecution stepExecution;
public void setUp() throws Exception {
MapJobInstanceDao.clear();
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
JobRepository jobRepository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
new MapStepExecutionDao());
JobSupport jobConfiguration = new JobSupport();
step = new ItemOrientedStep("interruptedStep");
jobConfiguration.addStep(step);
jobConfiguration.setBeanName("testJob");
jobExecution = jobRepository.createJobExecution(jobConfiguration, new JobParameters());
step.setJobRepository(jobRepository);
step.setTransactionManager(new ResourcelessTransactionManager());
itemWriter = new AbstractItemWriter() {
public void write(Object item) throws Exception {
}
};
step.setItemHandler(new SimpleItemHandler(new AbstractItemReader() {
public Object read() throws Exception {
return null;
}
}, itemWriter));
stepExecution = new StepExecution(step, jobExecution);
}
public void testInterruptChunk() throws Exception {
Thread processingThread = createThread(stepExecution);
processingThread.start();
Thread.sleep(100);
processingThread.interrupt();
int count = 0;
while (processingThread.isAlive() && count < 1000) {
Thread.sleep(20);
count++;
}
assertTrue("Timed out waiting for step to be interrupted.", count < 1000);
assertFalse(processingThread.isAlive());
assertEquals(BatchStatus.STOPPED, stepExecution.getStatus());
}
public void testInterruptStep() throws Exception {
RepeatTemplate template = new RepeatTemplate();
// N.B, If we don't set the completion policy it might run forever
template.setCompletionPolicy(new SimpleCompletionPolicy(2));
step.setChunkOperations(template);
testInterruptChunk();
}
public void testInterruptOnInterruptedException() throws Exception {
Thread processingThread = createThread(stepExecution);
step.setItemHandler(new SimpleItemHandler(new AbstractItemReader() {
public Object read() throws Exception {
return null;
}
}, itemWriter));
// This simulates the unlikely sounding, but in practice all too common
// in Bamboo situation where the thread is interrupted before the lock
// is taken.
step.setSynchronizer(new StepExecutionSynchronizer() {
public void lock(StepExecution stepExecution) throws InterruptedException {
Thread.currentThread().interrupt();
throw new InterruptedException();
}
public void release(StepExecution stepExecution) {
}
});
processingThread.start();
Thread.sleep(100);
int count = 0;
while (processingThread.isAlive() && count < 1000) {
Thread.sleep(20);
count++;
}
assertTrue("Timed out waiting for step to be interrupted.", count < 1000);
assertFalse(processingThread.isAlive());
assertEquals(BatchStatus.STOPPED, stepExecution.getStatus());
}
/**
* @return
*/
private Thread createThread(final StepExecution stepExecution) {
step.setItemHandler(new SimpleItemHandler(new AbstractItemReader() {
public Object read() throws Exception {
// do something non-trivial (and not Thread.sleep())
double foo = 1;
for (int i = 2; i < 250; i++) {
foo = foo * i;
}
if (foo != 1) {
return new Double(foo);
}
else {
return null;
}
}
}, itemWriter));
Thread processingThread = new Thread() {
public void run() {
try {
step.execute(stepExecution);
}
catch (JobInterruptedException e) {
// do nothing...
}
}
};
return processingThread;
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.execution.step.support;
import junit.framework.TestCase;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.execution.step.support.ThreadStepInterruptionPolicy;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.context.RepeatContextSupport;
/**
* @author Dave Syer
*
*/
public class ThreadStepInterruptionPolicyTests extends TestCase {
ThreadStepInterruptionPolicy policy = new ThreadStepInterruptionPolicy();
private RepeatContext context = new RepeatContextSupport(null);;
/**
* Test method for {@link org.springframework.batch.core.executor.interrupt.ThreadStepInterruptionPolicy#checkInterrupted(org.springframework.batch.repeat.RepeatContext)}.
* @throws Exception
*/
public void testCheckInterruptedNotComplete() throws Exception {
policy.checkInterrupted(context);
// no exception
}
/**
* Test method for {@link org.springframework.batch.core.executor.interrupt.ThreadStepInterruptionPolicy#checkInterrupted(org.springframework.batch.repeat.RepeatContext)}.
* @throws Exception
*/
public void testCheckInterruptedComplete() throws Exception {
context.setTerminateOnly();
try {
policy.checkInterrupted(context);
fail("Expected StepInterruptedException");
} catch (JobInterruptedException e) {
// expected
assertTrue(e.getMessage().indexOf("interrupt")>=0);
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.execution.tasklet;
import org.springframework.batch.repeat.ExitStatus;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class TaskletAdapterTests extends TestCase {
private TaskletAdapter tasklet = new TaskletAdapter();
private Object result = null;
public ExitStatus execute() {
return ExitStatus.NOOP;
}
public Object process() {
return result ;
}
/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
tasklet.setTargetObject(this);
tasklet.setTargetMethod("execute");
}
/**
* Test method for {@link org.springframework.batch.execution.tasklet.TaskletAdapter#execute()}.
* @throws Exception
*/
public void testExecuteWithExitStatus() throws Exception {
assertEquals(ExitStatus.NOOP, tasklet.execute());
}
/**
* Test method for {@link org.springframework.batch.execution.tasklet.TaskletAdapter#mapResult(java.lang.Object)}.
*/
public void testMapResultWithNull() throws Exception {
tasklet.setTargetMethod("process");
assertEquals(ExitStatus.FINISHED, tasklet.execute());
}
/**
* Test method for {@link org.springframework.batch.execution.tasklet.TaskletAdapter#mapResult(java.lang.Object)}.
*/
public void testMapResultWithNonNull() throws Exception {
tasklet.setTargetMethod("process");
this.result = "foo";
assertEquals(ExitStatus.CONTINUABLE, tasklet.execute());
}
}

View File

@@ -0,0 +1,156 @@
/*
* 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 test.jdbc.datasource;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
private Resource[] initScripts;
private Resource destroyScript;
DataSource dataSource;
private static boolean initialized = false;
/**
* @throws Throwable
* @see java.lang.Object#finalize()
*/
protected void finalize() throws Throwable {
super.finalize();
initialized = false;
logger.debug("finalize called");
}
protected void destroyInstance(Object instance) throws Exception {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.warn("Could not execute destroy script [" + destroyScript + "]", e);
}
else {
logger.warn("Could not execute destroy script [" + destroyScript + "]");
}
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource);
super.afterPropertiesSet();
}
protected Object createInstance() throws Exception {
Assert.notNull(dataSource);
if (!initialized) {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
logger.debug("Could not execute destroy script [" + destroyScript + "]", e);
}
if (initScripts != null) {
for (int i = 0; i < initScripts.length; i++) {
Resource initScript = initScripts[i];
doExecuteScript(initScript);
}
}
initialized = true;
}
return dataSource;
}
private void doExecuteScript(final Resource scriptResource) {
if (scriptResource == null || !scriptResource.exists())
return;
TransactionTemplate transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] scripts;
try {
scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource
.getInputStream())), ";");
}
catch (IOException e) {
throw new BeanInitializationException("Cannot load script from [" + scriptResource + "]", e);
}
for (int i = 0; i < scripts.length; i++) {
String script = scripts[i].trim();
if (StringUtils.hasText(script)) {
jdbcTemplate.execute(scripts[i]);
}
}
return null;
}
});
}
private String stripComments(List list) {
StringBuffer buffer = new StringBuffer();
for (Iterator iter = list.iterator(); iter.hasNext();) {
String line = (String) iter.next();
if (!line.startsWith("//") && !line.startsWith("--")) {
buffer.append(line + "\n");
}
}
return buffer.toString();
}
public Class getObjectType() {
return DataSource.class;
}
public void setInitScript(Resource initScript) {
this.initScripts = new Resource[] { initScript };
}
public void setInitScripts(Resource[] initScripts) {
this.initScripts = initScripts;
}
public void setDestroyScript(Resource destroyScript) {
this.destroyScript = destroyScript;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}