REOPENED - issue BATCH-511: read failures cause rollback

Add SkipLimitExceededException to the list of fatal exceptions for the step exception handler
This commit is contained in:
dsyer
2008-03-27 06:41:37 +00:00
parent a727ec76e2
commit 914b9f2bed
7 changed files with 197 additions and 47 deletions

View File

@@ -68,7 +68,7 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
catch (SkippableException e) {
// expected
}
assertEquals(0, contribution.getContributionSkipCount());
assertEquals(0, contribution.getSkipCount());
assertEquals(new Holder("3"), handler.read(contribution));
}
@@ -76,7 +76,7 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
assertEquals(new Holder("1"), handler.read(contribution));
assertEquals(new Holder("3"), handler.read(contribution));
assertEquals(1, contribution.getContributionSkipCount());
assertEquals(1, contribution.getSkipCount());
assertEquals(new Holder("4"), handler.read(contribution));
}
@@ -89,14 +89,14 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
catch (SkippableException e) {
// expected
}
assertEquals(0, contribution.getContributionSkipCount());
assertEquals(0, contribution.getSkipCount());
}
public void testHandleWithSkip() throws Exception {
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
handler.handle(contribution);
handler.handle(contribution);
assertEquals(1, contribution.getContributionSkipCount());
assertEquals(1, contribution.getSkipCount());
// 2 is skipped so 3 was last one processed and now we are at 4
try {
handler.handle(contribution);
@@ -105,7 +105,7 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
catch (SkippableException e) {
// expected
}
assertEquals(2, contribution.getContributionSkipCount());
assertEquals(2, contribution.getSkipCount());
// No "4" because it was skipped on write
assertEquals(new Holder("5"), handler.read(contribution));
}
@@ -121,11 +121,11 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
}
handler.handle(contribution);
handler.handle(contribution);
assertEquals(2, contribution.getContributionSkipCount());
assertEquals(2, contribution.getSkipCount());
// 2 is skipped so 3 was last one processed and now we are at 4, which was previously skipped
handler.handle(contribution);
assertEquals(null, handler.read(contribution));
assertEquals(2, contribution.getContributionSkipCount());
assertEquals(2, contribution.getSkipCount());
assertEquals(1, TransactionSynchronizationManager.getResourceMap().size());
Set removed = (Set) TransactionSynchronizationManager.getResourceMap().values().iterator().next();
@@ -151,10 +151,10 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
catch (SkippableException e) {
// expected
}
assertEquals(1, contribution.getContributionSkipCount());
assertEquals(1, contribution.getSkipCount());
assertEquals(new Holder("1"), handler.read(contribution));
assertEquals(new Holder("3"), handler.read(contribution));
assertEquals(2, contribution.getContributionSkipCount());
assertEquals(2, contribution.getSkipCount());
// No "4" because it was skipped on write
assertEquals(new Holder("5"), handler.read(contribution));
}
@@ -165,7 +165,7 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
handler.handle(contribution);
handler.handle(contribution);
assertEquals(1, contribution.getContributionSkipCount());
assertEquals(1, contribution.getSkipCount());
// 2 is skipped so 3 was last one processed and now we are at 4
try {
handler.handle(contribution);
@@ -174,7 +174,7 @@ public class ItemSkipPolicyItemHandlerTests extends TestCase {
catch (SkippableException e) {
// expected
}
assertEquals(2, contribution.getContributionSkipCount());
assertEquals(2, contribution.getSkipCount());
// No "4" because it was skipped on write, even though it is mutating
// its key
assertEquals(new Holder("5"), handler.read(contribution));

View File

@@ -1,7 +1,9 @@
package org.springframework.batch.core.step.item;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
@@ -12,6 +14,7 @@ import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.step.JobRepositorySupport;
import org.springframework.batch.core.step.skip.SkipLimitExceededException;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemReader;
@@ -22,13 +25,14 @@ import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.ResetFailedException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.util.StringUtils;
/**
* Tests for {@link SkipLimitStepFactoryBean}.
*/
public class SkipLimitStepFactoryBeanTests extends TestCase {
SkipLimitStepFactoryBean tested = new SkipLimitStepFactoryBean();
SkipLimitStepFactoryBean factory = new SkipLimitStepFactoryBean();
Class[] skippableExceptions = new Class[] { SkippableException.class, SkippableRuntimeException.class };
@@ -43,13 +47,13 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
JobExecution jobExecution;
protected void setUp() throws Exception {
tested.setJobRepository(new JobRepositorySupport());
tested.setTransactionManager(new ResourcelessTransactionManager());
tested.setCommitInterval(COMMIT_INTERVAL);
tested.setItemReader(reader);
tested.setItemWriter(writer);
tested.setSkippableExceptionClasses(skippableExceptions);
tested.setSkipLimit(SKIP_LIMIT);
factory.setJobRepository(new JobRepositorySupport());
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.setCommitInterval(COMMIT_INTERVAL);
factory.setItemReader(reader);
factory.setItemWriter(writer);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setSkipLimit(SKIP_LIMIT);
JobInstance jobInstance = new JobInstance(new Long(1), new JobParameters(), new JobSupport("skipJob"));
jobExecution = new JobExecution(jobInstance);
@@ -59,7 +63,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
* Check items causing errors are skipped as expected.
*/
public void testSkip() throws Exception {
ItemOrientedStep step = (ItemOrientedStep) tested.getObject();
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
StepExecution stepExecution = new StepExecution(step, jobExecution);
step.execute(stepExecution);
@@ -70,13 +74,8 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
assertTrue(reader.processed.contains("4"));
assertFalse(writer.written.contains("4"));
String[] expectedOutput = { "1", "3", "5" };
for (int i = 0; i < expectedOutput.length; i++) {
assertTrue("Output should contain \"" + expectedOutput[i] + "\"", writer.written
.contains(expectedOutput[i]));
}
assertTrue(writer.written.size() == expectedOutput.length);
List expectedOutput = Arrays.asList(StringUtils.commaDelimitedListToStringArray("1,3,5"));
assertEquals(expectedOutput, writer.written);
}
@@ -85,14 +84,14 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
* skip settings (note the fatal exception is also classified as skippable).
*/
public void testFatalException() throws Exception {
tested.setFatalExceptionClasses(new Class[] { FatalRuntimeException.class });
tested.setItemWriter(new SkipWriterStub() {
factory.setFatalExceptionClasses(new Class[] { FatalRuntimeException.class });
factory.setItemWriter(new SkipWriterStub() {
public void write(Object item) {
throw new FatalRuntimeException("Ouch!");
}
});
ItemOrientedStep step = (ItemOrientedStep) tested.getObject();
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
StepExecution stepExecution = new StepExecution(step, jobExecution);
try {
@@ -104,26 +103,105 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
}
}
/**
* Check items causing errors are skipped as expected.
*/
public void testSkipOverLimit() throws Exception {
factory.setSkipLimit(1);
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
StepExecution stepExecution = new StepExecution(step, jobExecution);
try {
step.execute(stepExecution);
fail("Expected SkipLimitExceededException.");
}
catch (SkipLimitExceededException e) {
}
assertEquals(1, stepExecution.getSkipCount());
// writer did not skip "2" as it never made it to writer, only "4" did
assertTrue(reader.processed.contains("4"));
assertFalse(writer.written.contains("4"));
// failure on "4" tripped the skip limit so we never got to "5"
List expectedOutput = Arrays.asList(StringUtils.commaDelimitedListToStringArray("1,3"));
assertEquals(expectedOutput, writer.written);
}
/**
* Check items causing errors are skipped as expected.
*/
public void testSkipOverLimitOnRead() throws Exception {
reader = new SkipReaderStub(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"), StringUtils
.commaDelimitedListToSet("2,3,5"));
factory.setSkipLimit(3);
factory.setItemReader(reader);
factory.setSkippableExceptionClasses(new Class[] {Exception.class});
ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
StepExecution stepExecution = new StepExecution(step, jobExecution);
try {
step.execute(stepExecution);
fail("Expected SkipLimitExceededException.");
}
catch (SkipLimitExceededException e) {
}
assertEquals(3, stepExecution.getSkipCount());
// writer did not skip "2" as it never made it to writer, only "4" did
assertTrue(reader.processed.contains("4"));
// failure on "4" tripped the skip limit so we never got to "5"
List expectedOutput = Arrays.asList(StringUtils.commaDelimitedListToStringArray("1"));
assertEquals(expectedOutput, writer.written);
}
/**
* Simple item reader that supports skip functionality.
*/
private static class SkipReaderStub implements ItemReader {
final String[] items = { "1", "2", "3", "4", "5", null };
private final String[] items;
Collection processed = new ArrayList();
private Collection processed = new ArrayList();
int counter = -1;
private int counter = -1;
int marked = 0;
private int marked = 0;
private final Collection failures;
public SkipReaderStub() {
this(new String[] { "1", "2", "3", "4", "5" }, Collections.singleton("2"));
}
public SkipReaderStub(String[] items, Collection failures) {
this.items = items;
this.failures = failures;
}
public Object read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
counter++;
if ("2".equals(items[counter])) {
if (counter >= items.length) {
return null;
}
String item = items[counter];
if (failures.contains(item)) {
throw new SkippableException("exception in reader");
}
processed.add(items[counter]);
return items[counter];
processed.add(item);
return item;
}
public void mark() throws MarkFailedException {