OPEN - issue BATCH-789: Remove mark/reset from ItemReader
Still some open issues with retry and skip, but nearly there...
This commit is contained in:
@@ -71,8 +71,8 @@ public class ItemOrientedStepHandlerTests {
|
||||
StepContribution contribution = new StepContribution(new StepExecution("foo", new JobExecution(new JobInstance(
|
||||
123L, new JobParameters(), "job"))));
|
||||
handler.handle(contribution);
|
||||
assertEquals(4, itemReader.count);
|
||||
assertEquals("1234", itemWriter.values);
|
||||
assertEquals(2, itemReader.count);
|
||||
assertEquals("12", itemWriter.values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,13 +46,9 @@ import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.repeat.RepeatContext;
|
||||
import org.springframework.batch.repeat.exception.ExceptionHandler;
|
||||
import org.springframework.batch.repeat.exception.SimpleLimitExceptionHandler;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
|
||||
/**
|
||||
@@ -131,22 +127,6 @@ public class SimpleStepFactoryBeanTests {
|
||||
@Test
|
||||
public void testSimpleJobWithItemListeners() throws Exception {
|
||||
|
||||
final List<Throwable> throwables = new ArrayList<Throwable>();
|
||||
|
||||
RepeatTemplate chunkOperations = new RepeatTemplate();
|
||||
// Always handle the exception to 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)...
|
||||
*/
|
||||
SimpleStepFactoryBean<String,String> factory = getStepFactory(new String[] { "foo", "bar", "spam" });
|
||||
|
||||
factory.setItemWriter(new ItemWriter<String>() {
|
||||
@@ -164,19 +144,24 @@ public class SimpleStepFactoryBeanTests {
|
||||
}
|
||||
} });
|
||||
|
||||
factory.setChunkOperations(chunkOperations);
|
||||
StepHandlerStep step = (StepHandlerStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
job.setSteps(Collections.singletonList((Step) step));
|
||||
job.setSteps(Collections.singletonList(step));
|
||||
|
||||
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
|
||||
job.execute(jobExecution);
|
||||
try {
|
||||
job.execute(jobExecution);
|
||||
fail("Expected RuntimeException");
|
||||
} catch (RuntimeException e) {
|
||||
// expected
|
||||
assertEquals("Error!", e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
|
||||
assertEquals(0, written.size());
|
||||
// provider should be exhausted
|
||||
assertEquals(null, reader.read());
|
||||
assertEquals(3, recovered.size());
|
||||
// provider should be at second item
|
||||
assertEquals("bar", reader.read());
|
||||
assertEquals(1, recovered.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -313,7 +298,7 @@ public class SimpleStepFactoryBeanTests {
|
||||
private SimpleStepFactoryBean<String,String> getStepFactory(String... args) throws Exception {
|
||||
SimpleStepFactoryBean<String,String> factory = new SimpleStepFactoryBean<String,String>();
|
||||
|
||||
List<String> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
List<String> items = new ArrayList<String>();
|
||||
items.addAll(Arrays.asList(args));
|
||||
reader = new ListItemReader<String>(items);
|
||||
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.StepListener;
|
||||
import org.springframework.batch.core.listener.SkipListenerSupport;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.JobRepositorySupport;
|
||||
import org.springframework.batch.core.step.skip.SkipLimitExceededException;
|
||||
import org.springframework.batch.core.step.skip.SkipListenerFailedException;
|
||||
import org.springframework.batch.item.ClearFailedException;
|
||||
import org.springframework.batch.item.FlushFailedException;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.MarkFailedException;
|
||||
@@ -38,7 +41,7 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Tests for {@link SkipLimitStepFactoryBean}.
|
||||
*/
|
||||
public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
public class SkipLimitStepFactoryBeanTests {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -58,7 +61,8 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
protected int count;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
factory.setBeanName("stepName");
|
||||
factory.setJobRepository(new JobRepositorySupport());
|
||||
factory.setTransactionManager(new ResourcelessTransactionManager());
|
||||
@@ -75,8 +79,10 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@Test
|
||||
public void testSkip() throws Exception {
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
@@ -103,13 +109,14 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
* Check skippable write exception does not cause rollback when included on
|
||||
* transaction attributes as "no rollback for".
|
||||
*/
|
||||
@Test
|
||||
public void testSkipWithoutRethrow() throws Exception {
|
||||
factory.setTransactionAttribute(new DefaultTransactionAttribute() {
|
||||
public boolean rollbackOn(Throwable ex) {
|
||||
return !(ex instanceof SkippableRuntimeException);
|
||||
};
|
||||
});
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
@@ -129,6 +136,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
* Fatal exception should cause immediate termination regardless of other
|
||||
* skip settings (note the fatal exception is also classified as skippable).
|
||||
*/
|
||||
@Test
|
||||
public void testFatalException() throws Exception {
|
||||
factory.setFatalExceptionClasses(new Class[] { FatalRuntimeException.class });
|
||||
factory.setItemWriter(new SkipWriterStub() {
|
||||
@@ -137,7 +145,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
});
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
try {
|
||||
@@ -152,11 +160,12 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@Test
|
||||
public void testSkipOverLimit() throws Exception {
|
||||
|
||||
factory.setSkipLimit(1);
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
@@ -182,17 +191,17 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSkipOverLimitOnRead() throws Exception {
|
||||
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), StringUtils
|
||||
.commaDelimitedListToSet("2,3,5"));
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), Arrays
|
||||
.asList(StringUtils.commaDelimitedListToStringArray("2,3,5")));
|
||||
|
||||
factory.setSkipLimit(3);
|
||||
factory.setItemReader(reader);
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
@@ -224,11 +233,11 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSkipListenerFailsOnRead() throws Exception {
|
||||
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), StringUtils
|
||||
.commaDelimitedListToSet("2,3,5"));
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), Arrays
|
||||
.asList(StringUtils.commaDelimitedListToStringArray("2,3,5")));
|
||||
|
||||
factory.setSkipLimit(3);
|
||||
factory.setItemReader(reader);
|
||||
@@ -240,7 +249,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
} });
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
@@ -261,11 +270,11 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSkipListenerFailsOnWrite() throws Exception {
|
||||
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), StringUtils
|
||||
.commaDelimitedListToSet("2,3,5"));
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), Arrays
|
||||
.asList(StringUtils.commaDelimitedListToStringArray("2,3,5")));
|
||||
|
||||
factory.setSkipLimit(3);
|
||||
factory.setItemReader(reader);
|
||||
@@ -277,7 +286,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
} });
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
@@ -289,8 +298,8 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
assertEquals("oops", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
assertEquals(1, stepExecution.getSkipCount());
|
||||
assertEquals(0, stepExecution.getReadSkipCount());
|
||||
assertEquals(3, stepExecution.getSkipCount());
|
||||
assertEquals(2, stepExecution.getReadSkipCount());
|
||||
assertEquals(1, stepExecution.getWriteSkipCount());
|
||||
|
||||
}
|
||||
@@ -298,16 +307,16 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSkipOnReadNotDoubleCounted() throws Exception {
|
||||
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), StringUtils
|
||||
.commaDelimitedListToSet("2,3,5"));
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), Arrays
|
||||
.asList(StringUtils.commaDelimitedListToStringArray("2,3,5")));
|
||||
|
||||
factory.setSkipLimit(4);
|
||||
factory.setItemReader(reader);
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = jobExecution.createStepExecution(step);
|
||||
|
||||
@@ -325,19 +334,19 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSkipOnWriteNotDoubleCounted() throws Exception {
|
||||
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6,7"), StringUtils
|
||||
.commaDelimitedListToSet("2,3"));
|
||||
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6,7"), Arrays
|
||||
.asList(StringUtils.commaDelimitedListToStringArray("2,3")));
|
||||
|
||||
writer = new SkipWriterStub(StringUtils.commaDelimitedListToSet("4,5"));
|
||||
writer = new SkipWriterStub(Arrays.asList(StringUtils.commaDelimitedListToStringArray("4,5")));
|
||||
|
||||
factory.setSkipLimit(4);
|
||||
factory.setItemReader(reader);
|
||||
factory.setItemWriter(writer);
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = jobExecution.createStepExecution(step);
|
||||
|
||||
@@ -354,15 +363,14 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testDefaultSkipPolicy() throws Exception {
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
factory.setSkipLimit(1);
|
||||
List<String> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
|
||||
ItemReader provider = new ListItemReader(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "a", "b", "c" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
count++;
|
||||
if ("b".equals(item)) {
|
||||
throw new RuntimeException("Read error - planned failure.");
|
||||
@@ -371,7 +379,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
};
|
||||
factory.setItemReader(provider);
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
@@ -381,6 +389,8 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
assertEquals(4, count);
|
||||
}
|
||||
|
||||
// TODO: test with transactional reader (e.g. list with tx proxy)
|
||||
|
||||
/**
|
||||
* Simple item reader that supports skip functionality.
|
||||
*/
|
||||
@@ -394,8 +404,6 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
private int counter = -1;
|
||||
|
||||
private int marked = 0;
|
||||
|
||||
private final Collection<String> failures;
|
||||
|
||||
public SkipReaderStub() {
|
||||
@@ -424,13 +432,9 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
|
||||
public void mark() throws MarkFailedException {
|
||||
logger.debug("Marked at count=" + counter);
|
||||
marked = counter;
|
||||
}
|
||||
|
||||
public void reset() throws ResetFailedException {
|
||||
counter = marked;
|
||||
logger.debug("Reset at count=" + counter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -442,6 +446,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
// simulate transactional output
|
||||
private List<Object> written = TransactionAwareProxyFactory.createTransactionalList();
|
||||
|
||||
private final Collection<String> failures;
|
||||
@@ -458,12 +463,6 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
this.failures = failures;
|
||||
}
|
||||
|
||||
public void clear() throws ClearFailedException {
|
||||
}
|
||||
|
||||
public void flush() throws FlushFailedException {
|
||||
}
|
||||
|
||||
public void write(List<? extends String> items) throws Exception {
|
||||
for (String item : items) {
|
||||
if (failures.contains(item)) {
|
||||
|
||||
@@ -15,15 +15,19 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
@@ -47,23 +51,24 @@ import org.springframework.batch.retry.RetryException;
|
||||
import org.springframework.batch.retry.policy.RetryCacheCapacityExceededException;
|
||||
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
|
||||
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 {
|
||||
public class StatefulRetryStepFactoryBeanTests {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SkipLimitStepFactoryBean<Object,Object> factory = new SkipLimitStepFactoryBean<Object,Object>();
|
||||
private SkipLimitStepFactoryBean<String, String> factory = new SkipLimitStepFactoryBean<String, String>();
|
||||
|
||||
private List<Object> recovered = new ArrayList<Object>();
|
||||
|
||||
private List<Object> processed = new ArrayList<Object>();
|
||||
|
||||
private List<Object> provided = new ArrayList<Object>();
|
||||
|
||||
int count = 0;
|
||||
|
||||
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
|
||||
@@ -71,17 +76,19 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
JobExecution jobExecution;
|
||||
|
||||
private ItemWriter<Object> processor = new ItemWriter<Object>() {
|
||||
public void write(List<? extends Object> data) throws Exception {
|
||||
private ItemWriter<String> processor = new ItemWriter<String>() {
|
||||
public void write(List<? extends String> data) throws Exception {
|
||||
processed.addAll(data);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see junit.framework.TestCase#setUp()
|
||||
*/
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
MapJobInstanceDao.clear();
|
||||
MapJobExecutionDao.clear();
|
||||
@@ -89,7 +96,7 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
factory.setBeanName("step");
|
||||
|
||||
factory.setItemReader(new ListItemReader<Object>(new ArrayList<Object>()));
|
||||
factory.setItemReader(new ListItemReader<String>(new ArrayList<String>()));
|
||||
factory.setItemWriter(processor);
|
||||
factory.setJobRepository(repository);
|
||||
factory.setTransactionManager(new ResourcelessTransactionManager());
|
||||
@@ -104,10 +111,12 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testType() throws Exception {
|
||||
assertEquals(Step.class, factory.getObjectType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValue() throws Exception {
|
||||
assertTrue(factory.getObject() instanceof Step);
|
||||
}
|
||||
@@ -120,12 +129,13 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testSuccessfulRetryWithReadFailure() throws Exception {
|
||||
List<Object> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
|
||||
ItemReader<Object> provider = new ListItemReader<Object>(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "a", "b", "c" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
provided.add(item);
|
||||
count++;
|
||||
if (count == 2) {
|
||||
throw new RuntimeException("Temporary error - retry for success.");
|
||||
@@ -143,19 +153,24 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
assertEquals(0, stepExecution.getSkipCount());
|
||||
|
||||
// b is processed twice, plus a, plus c, plus the null at end
|
||||
assertEquals(5, count);
|
||||
assertEquals(3, stepExecution.getItemCount());
|
||||
// [a, b, c, null]
|
||||
assertEquals(4, provided.size());
|
||||
// [a, c]
|
||||
assertEquals(2, processed.size());
|
||||
// []
|
||||
assertEquals(0, recovered.size());
|
||||
assertEquals(2, stepExecution.getItemCount());
|
||||
assertEquals(0, stepExecution.getReadSkipCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipAndRetry() throws Exception {
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
factory.setSkipLimit(2);
|
||||
List<Object> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
|
||||
ItemReader<Object> provider = new ListItemReader<Object>(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
count++;
|
||||
if ("b".equals(item) || "d".equals(item)) {
|
||||
throw new RuntimeException("Read error - planned but skippable.");
|
||||
@@ -165,7 +180,7 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
};
|
||||
factory.setItemReader(provider);
|
||||
factory.setRetryLimit(10);
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
@@ -176,6 +191,7 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
assertEquals(4, stepExecution.getItemCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipAndRetryWithWriteFailure() throws Exception {
|
||||
|
||||
factory.setSkippableExceptionClasses(new Class[] { RetryException.class });
|
||||
@@ -186,22 +202,23 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
} });
|
||||
factory.setSkipLimit(2);
|
||||
List<Object> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
|
||||
ItemReader<Object> provider = new ListItemReader<Object>(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
logger.debug("Read Called! Item: [" + item + "]");
|
||||
provided.add(item);
|
||||
count++;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
ItemWriter<Object> itemWriter = new ItemWriter<Object>() {
|
||||
public void write(List<? extends Object> item) throws Exception {
|
||||
ItemWriter<String> itemWriter = new ItemWriter<String>() {
|
||||
public void write(List<? extends String> item) throws Exception {
|
||||
logger.debug("Write Called! Item: [" + item + "]");
|
||||
processed.addAll(item);
|
||||
if (item.contains("b") || item.contains("d")) {
|
||||
throw new RuntimeException("Read error - planned but skippable.");
|
||||
throw new RuntimeException("Write error - planned but recoverable.");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -217,33 +234,39 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
assertEquals(2, recovered.size());
|
||||
assertEquals(2, stepExecution.getSkipCount());
|
||||
assertEquals(2, stepExecution.getWriteSkipCount());
|
||||
// each item once, plus 5 failed retries each for b and d, plus the null
|
||||
// terminator
|
||||
assertEquals(17, count);
|
||||
|
||||
// [a, b, c, d, e, f, null]
|
||||
assertEquals(7, provided.size());
|
||||
// [a, b, b, b, b, b, c, d, d, d, d, d, e, f]
|
||||
assertEquals(14, processed.size());
|
||||
// [b, d]
|
||||
assertEquals(2, recovered.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetryWithNoSkip() throws Exception {
|
||||
factory.setRetryableExceptionClasses(new Class[] { Exception.class });
|
||||
factory.setRetryLimit(4);
|
||||
factory.setSkipLimit(0);
|
||||
List<Object> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "b" }));
|
||||
ItemReader<Object> provider = new ListItemReader<Object>(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "b" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
provided.add(item);
|
||||
count++;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
ItemWriter<Object> itemWriter = new ItemWriter<Object>() {
|
||||
public void write(List<? extends Object> item) throws Exception {
|
||||
ItemWriter<String> itemWriter = new ItemWriter<String>() {
|
||||
public void write(List<? extends String> item) throws Exception {
|
||||
processed.addAll(item);
|
||||
logger.debug("Write Called! Item: [" + item + "]");
|
||||
throw new RuntimeException("Write error - planned but retryable.");
|
||||
}
|
||||
};
|
||||
factory.setItemReader(provider);
|
||||
factory.setItemWriter(itemWriter);
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
try {
|
||||
@@ -255,25 +278,31 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
|
||||
assertEquals(0, stepExecution.getSkipCount());
|
||||
// b is processed 4 times plus the null at end
|
||||
assertEquals(5, count);
|
||||
// [b]
|
||||
assertEquals(1, provided.size());
|
||||
// [b, b, b, b]
|
||||
assertEquals(4, processed.size());
|
||||
// []
|
||||
assertEquals(0, recovered.size());
|
||||
assertEquals(0, stepExecution.getItemCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetryPolicy() throws Exception {
|
||||
factory.setRetryPolicy(new SimpleRetryPolicy(4));
|
||||
factory.setSkipLimit(0);
|
||||
List<Object> items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "b" }));
|
||||
ItemReader<Object> provider = new ListItemReader<Object>(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
List<String> items = Arrays.asList(new String[] { "b" });
|
||||
ItemReader<String> provider = new ListItemReader<String>(items) {
|
||||
public String read() {
|
||||
String item = super.read();
|
||||
provided.add(item);
|
||||
count++;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
ItemWriter<Object> itemWriter = new ItemWriter<Object>() {
|
||||
public void write(List<? extends Object> item) throws Exception {
|
||||
ItemWriter<String> itemWriter = new ItemWriter<String>() {
|
||||
public void write(List<? extends String> item) throws Exception {
|
||||
processed.addAll(item);
|
||||
logger.debug("Write Called! Item: [" + item + "]");
|
||||
throw new RuntimeException("Write error - planned but retryable.");
|
||||
}
|
||||
@@ -292,26 +321,39 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
}
|
||||
|
||||
assertEquals(0, stepExecution.getSkipCount());
|
||||
// b is processed 4 times plus the null at end
|
||||
assertEquals(5, count);
|
||||
// [b]
|
||||
assertEquals(1, provided.size());
|
||||
// [b, b, b, b]
|
||||
assertEquals(4, processed.size());
|
||||
// []
|
||||
assertEquals(0, recovered.size());
|
||||
assertEquals(0, stepExecution.getItemCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheLimitWithRetry() throws Exception {
|
||||
factory.setRetryableExceptionClasses(new Class[] { Exception.class });
|
||||
factory.setRetryLimit(2);
|
||||
factory.setCommitInterval(3);
|
||||
// sufficiently high so we never hit it
|
||||
factory.setSkipLimit(10);
|
||||
// set the cache limit lower than the number of unique un-recovered
|
||||
// errors expected
|
||||
factory.setCacheCapacity(2);
|
||||
ItemReader<Object> provider = new AbstractItemReader<Object>() {
|
||||
public Object read() {
|
||||
Object item = new Object();
|
||||
ItemReader<String> provider = new AbstractItemReader<String>() {
|
||||
public String read() {
|
||||
String item = ""+count;
|
||||
provided.add(item);
|
||||
count++;
|
||||
if (count >= 10) {
|
||||
// prevent infinite loop in worst case scenario
|
||||
return null;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
};
|
||||
ItemWriter<Object> itemWriter = new ItemWriter<Object>() {
|
||||
public void write(List<? extends Object> item) throws Exception {
|
||||
ItemWriter<String> itemWriter = new ItemWriter<String>() {
|
||||
public void write(List<? extends String> item) throws Exception {
|
||||
processed.addAll(item);
|
||||
logger.debug("Write Called! Item: [" + item + "]");
|
||||
throw new RuntimeException("Write error - planned but retryable.");
|
||||
}
|
||||
@@ -329,8 +371,14 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
// expected
|
||||
}
|
||||
|
||||
assertEquals(0, stepExecution.getSkipCount());
|
||||
// 2 processed and cached, 3rd barfed because cache was full
|
||||
assertEquals(3, count);
|
||||
assertEquals(1, stepExecution.getSkipCount());
|
||||
// only one item processed but three (the commit interval) were provided
|
||||
// [0, 1, 2]
|
||||
assertEquals(3, provided.size());
|
||||
// TODO: this is a bug: 0 was skipped but it came back in the buffer for the second try
|
||||
// [0, 0, 1, 0, 0]
|
||||
assertEquals(5, processed.size());
|
||||
// []
|
||||
assertEquals(0, recovered.size());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user