OPEN - issue BATCH-753: Listener exception handling
Add test for SkipListenerFailedException
This commit is contained in:
@@ -16,15 +16,19 @@
|
||||
|
||||
package org.springframework.batch.core;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public abstract class AbstractExceptionTests extends TestCase {
|
||||
import org.junit.Test;
|
||||
|
||||
public abstract class AbstractExceptionTests {
|
||||
|
||||
@Test
|
||||
public void testExceptionString() throws Exception {
|
||||
Exception exception = getException("foo");
|
||||
assertEquals("foo", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionStringThrowable() throws Exception {
|
||||
Exception exception = getException("foo", new IllegalStateException());
|
||||
assertEquals("foo", exception.getMessage().substring(0, 3));
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.listener;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractDoubleExceptionTests {
|
||||
|
||||
@Test
|
||||
public void testExceptionStringThrowable() throws Exception {
|
||||
Exception exception = getException("foo", new IllegalStateException(), new RuntimeException("bar"));
|
||||
assertEquals("foo", exception.getMessage().substring(0, 3));
|
||||
}
|
||||
|
||||
public abstract Exception getException(String msg, RuntimeException cause, Throwable e) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.listener;
|
||||
|
||||
import org.springframework.batch.core.step.skip.SkipListenerFailedException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class StepListenerFailedExceptionTests extends AbstractDoubleExceptionTests {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.listener.AbstractDoubleExceptionTests#getException(java.lang.String, java.lang.Throwable, java.lang.Throwable)
|
||||
*/
|
||||
@Override
|
||||
public Exception getException(String msg, RuntimeException cause, Throwable e) throws Exception {
|
||||
return new SkipListenerFailedException(msg, cause, e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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.SkipListener;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.UnexpectedJobExecutionException;
|
||||
import org.springframework.batch.core.listener.SkipListenerSupport;
|
||||
import org.springframework.batch.core.step.StepSupport;
|
||||
import org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy;
|
||||
import org.springframework.batch.item.ClearFailedException;
|
||||
import org.springframework.batch.item.FlushFailedException;
|
||||
import org.springframework.batch.item.ItemKeyGenerator;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.MarkFailedException;
|
||||
import org.springframework.batch.item.NoWorkFoundException;
|
||||
import org.springframework.batch.item.ParseException;
|
||||
import org.springframework.batch.item.ResetFailedException;
|
||||
import org.springframework.batch.item.UnexpectedInputException;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ItemSkipPolicyItemHandlerTests extends TestCase {
|
||||
|
||||
private final SkipWriterStub writer = new SkipWriterStub();
|
||||
|
||||
private ItemSkipPolicyItemHandler<Holder> handler = new ItemSkipPolicyItemHandler<Holder>(new SkipReaderStub(), writer);
|
||||
|
||||
private StepContribution contribution = new StepContribution(new JobExecution(new JobInstance(new Long(11),
|
||||
new JobParameters(), "jobName")).createStepExecution(new StepSupport("foo")));
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
// remove the resource if it exists
|
||||
handler.mark();
|
||||
}
|
||||
|
||||
public void testReadWithNoSkip() throws Exception {
|
||||
assertEquals(new Holder("1"), handler.read(contribution));
|
||||
try {
|
||||
handler.read(contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(0, contribution.getSkipCount());
|
||||
assertEquals(new Holder("3"), handler.read(contribution));
|
||||
}
|
||||
|
||||
public void testReadWithSkip() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
assertEquals(new Holder("1"), handler.read(contribution));
|
||||
assertEquals(new Holder("3"), handler.read(contribution));
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(1, contribution.getReadSkipCount());
|
||||
assertEquals(new Holder("4"), handler.read(contribution));
|
||||
}
|
||||
|
||||
public void testWriteWithNoSkip() throws Exception {
|
||||
handler.write(new Holder("3"), contribution);
|
||||
try {
|
||||
handler.write(new Holder("4"), contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(0, contribution.getSkipCount());
|
||||
}
|
||||
|
||||
public void testHandleWithSkip() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.handle(contribution);
|
||||
handler.handle(contribution);
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(1, contribution.getSkipCount());
|
||||
// 2 is skipped so 3 was last one processed and now we are at 4
|
||||
try {
|
||||
handler.handle(contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
assertEquals(3, contribution.getItemCount());
|
||||
assertEquals(2, contribution.getSkipCount());
|
||||
// No "4" because it was skipped on write
|
||||
assertEquals(new Holder("5"), handler.read(contribution));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testWriteWithSkipAfterMark() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
try {
|
||||
handler.write(new Holder("4"), contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
handler.handle(contribution);
|
||||
handler.handle(contribution);
|
||||
contribution.combineSkipCounts();
|
||||
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(3, contribution.getItemCount());
|
||||
assertEquals(2, contribution.getSkipCount());
|
||||
|
||||
assertEquals(1, TransactionSynchronizationManager.getResourceMap().size());
|
||||
Set<Object> removed = (Set<Object>) TransactionSynchronizationManager.getResourceMap().values().iterator().next();
|
||||
// one skipped item was detected on read
|
||||
assertEquals(1, removed.size());
|
||||
// mark() should remove the set of removed keys
|
||||
handler.mark();
|
||||
assertEquals(0, TransactionSynchronizationManager.getResourceMap().size());
|
||||
}
|
||||
|
||||
public void testWriteWithSkipAndItemKeyGenerator() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.setItemKeyGenerator(new ItemKeyGenerator() {
|
||||
public Object getKey(Object item) {
|
||||
return ((Holder) item).value;
|
||||
}
|
||||
});
|
||||
handler.write(new Holder("3"), contribution);
|
||||
try {
|
||||
handler.write(new Holder("4"), contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(1, contribution.getSkipCount());
|
||||
assertEquals(new Holder("1"), handler.read(contribution));
|
||||
assertEquals(new Holder("3"), handler.read(contribution));
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(2, contribution.getSkipCount());
|
||||
// No "4" because it was skipped on write
|
||||
assertEquals(new Holder("5"), handler.read(contribution));
|
||||
}
|
||||
|
||||
public void testWriteWithSkipWhenMutating() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
writer.mutate = true;
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.handle(contribution);
|
||||
handler.handle(contribution);
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(1, contribution.getSkipCount());
|
||||
// 2 is skipped so 3 was last one processed and now we are at 4
|
||||
try {
|
||||
handler.handle(contribution);
|
||||
fail("Expected SkippableException");
|
||||
}
|
||||
catch (SkippableException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(3, contribution.getItemCount());
|
||||
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));
|
||||
}
|
||||
|
||||
public void testWriteWithSkipCapacityBreached() throws Exception {
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.setSkipCacheCapacity(0);
|
||||
handler.handle(contribution);
|
||||
handler.handle(contribution);
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(1, contribution.getSkipCount());
|
||||
// 2 is skipped so 3 was last one processed and now we are at 4
|
||||
try {
|
||||
handler.handle(contribution);
|
||||
fail("Expected UnexpectedJobExecutionException");
|
||||
}
|
||||
catch (UnexpectedJobExecutionException e) {
|
||||
// expected
|
||||
String message = e.getMessage();
|
||||
assertTrue("Message does not contain 'capacity': " + message, message.indexOf("capacity") >= 0);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Skippable write exceptions are not re-thrown when included in the
|
||||
* {@link ItemSkipPolicyItemHandler#setDoNotRethrowExceptionClasses(Class[])}
|
||||
*/
|
||||
public void testWriteWithSkipAndDoNotRethrow() throws Exception {
|
||||
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.setDoNotRethrowExceptionClasses(new Class[] { SkippableException.class });
|
||||
|
||||
handler.handle(contribution);
|
||||
handler.handle(contribution);
|
||||
contribution.combineSkipCounts();
|
||||
assertEquals(1, contribution.getSkipCount());
|
||||
|
||||
// skippable exception thrown in writer at this point, but it won't be
|
||||
// re-thrown
|
||||
handler.handle(contribution);
|
||||
|
||||
assertEquals(3, contribution.getItemCount());
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SkipListener#onSkipInWrite(Object, Throwable)} should be called
|
||||
* also if the exception is not re-thrown (does not cause rollback).
|
||||
*/
|
||||
public void testHandleWithSkipAndListeners() throws Exception {
|
||||
|
||||
class SkipOnWriteListener extends SkipListenerSupport {
|
||||
|
||||
boolean called = false;
|
||||
|
||||
public void onSkipInWrite(Object item, Throwable t) {
|
||||
called = true;
|
||||
}
|
||||
|
||||
}
|
||||
;
|
||||
SkipOnWriteListener skipOnWriteListener = new SkipOnWriteListener();
|
||||
handler.setSkipListeners(new SkipListener[] { skipOnWriteListener });
|
||||
handler.setDoNotRethrowExceptionClasses(new Class[] { SkippableException.class });
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
for (int i = 0; i < 5; i++) {
|
||||
handler.handle(contribution);
|
||||
}
|
||||
assertTrue("onSkipInWrite should be called although the exception is not re-thrown", skipOnWriteListener.called);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple item reader that supports skip functionality.
|
||||
*/
|
||||
private static class SkipReaderStub implements ItemReader<Holder> {
|
||||
|
||||
final String[] values = { "1", "2", "3", "4", "5" };
|
||||
|
||||
Collection<Object> processed = new ArrayList<Object>();
|
||||
|
||||
int counter = -1;
|
||||
|
||||
int marked = 0;
|
||||
|
||||
public Holder read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
|
||||
counter++;
|
||||
if (counter == 1) {
|
||||
throw new SkippableException("exception in reader");
|
||||
}
|
||||
if (counter >= values.length) {
|
||||
return null;
|
||||
}
|
||||
Holder item = new Holder(values[counter]);
|
||||
processed.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public void mark() throws MarkFailedException {
|
||||
marked = counter;
|
||||
}
|
||||
|
||||
public void reset() throws ResetFailedException {
|
||||
counter = marked;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple item writer that supports skip functionality.
|
||||
*/
|
||||
private static class SkipWriterStub implements ItemWriter<Holder> {
|
||||
|
||||
boolean mutate = false;
|
||||
|
||||
List<Object> written = new ArrayList<Object>();
|
||||
|
||||
int flushIndex = -1;
|
||||
|
||||
public void clear() throws ClearFailedException {
|
||||
for (int i = flushIndex + 1; i < written.size(); i++) {
|
||||
written.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws FlushFailedException {
|
||||
flushIndex = written.size() - 1;
|
||||
}
|
||||
|
||||
public void write(Holder item) throws Exception {
|
||||
String value = item.value;
|
||||
written.add(item);
|
||||
if (mutate) {
|
||||
item.value = "done";
|
||||
}
|
||||
if (value.equals("4")) {
|
||||
throw new SkippableException("exception in writer");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SkippableException extends Exception {
|
||||
public SkippableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Holder {
|
||||
private String value = null;
|
||||
|
||||
public Holder(String value) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Holder && value.equals(((Holder) obj).value);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[holder:" + value + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,27 +15,31 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.step.skip.LimitCheckingItemSkipPolicy;
|
||||
import org.springframework.batch.core.step.skip.SkipLimitExceededException;
|
||||
import org.springframework.batch.item.file.FlatFileParseException;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SkipLimitReadFailurePolicyTests extends TestCase {
|
||||
public class LimitCheckingItemSkipPolicyTests {
|
||||
|
||||
private LimitCheckingItemSkipPolicy failurePolicy;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
List<Class<?>> skippableExceptions = new ArrayList<Class<?>>();
|
||||
skippableExceptions.add(FlatFileParseException.class);
|
||||
List<Class<?>> fatalExceptions = new ArrayList<Class<?>>();
|
||||
@@ -43,6 +47,7 @@ public class SkipLimitReadFailurePolicyTests extends TestCase {
|
||||
failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLimitExceed(){
|
||||
try{
|
||||
failurePolicy.shouldSkip(new FlatFileParseException("", ""), 2);
|
||||
@@ -53,10 +58,12 @@ public class SkipLimitReadFailurePolicyTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSkippableException(){
|
||||
assertFalse(failurePolicy.shouldSkip(new FileNotFoundException(), 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkip(){
|
||||
assertTrue(failurePolicy.shouldSkip(new FlatFileParseException("",""), 0));
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.MarkFailedException;
|
||||
import org.springframework.batch.item.ResetFailedException;
|
||||
|
||||
public class MockItemReader implements ItemReader<String> {
|
||||
|
||||
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 String read() {
|
||||
if(fail) {
|
||||
fail = false;
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
if (returnItemCount < 0 || returnedItemCount < returnItemCount) {
|
||||
return String.valueOf(returnedItemCount++);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getKey(Object item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void mark() throws MarkFailedException {
|
||||
}
|
||||
|
||||
public void reset() throws ResetFailedException {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,12 @@ import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
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;
|
||||
@@ -91,7 +94,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
List<String> expectedOutput = Arrays.asList(StringUtils.commaDelimitedListToStringArray("1,3,5"));
|
||||
assertEquals(expectedOutput, writer.written);
|
||||
|
||||
|
||||
assertEquals(4, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
@@ -117,7 +120,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
// no rollbacks
|
||||
assertEquals(0, stepExecution.getRollbackCount().intValue());
|
||||
|
||||
|
||||
assertEquals(4, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
@@ -208,14 +211,90 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
assertFalse(reader.processed.contains("2"));
|
||||
assertTrue(reader.processed.contains("4"));
|
||||
|
||||
// failure on "5" tripped the skip limit but "4" failed on write and was skipped and
|
||||
// RepeatSynchronizationManager.setCompleteOnly() was called in the retry policy to
|
||||
// failure on "5" tripped the skip limit but "4" failed on write and was
|
||||
// skipped and
|
||||
// RepeatSynchronizationManager.setCompleteOnly() was called in the
|
||||
// retry policy to
|
||||
// aggressively commit after a recovery ("1" was written at that point)
|
||||
List<String> expectedOutput = Arrays.asList(StringUtils.commaDelimitedListToStringArray("1"));
|
||||
assertEquals(expectedOutput, writer.written);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSkipListenerFailsOnRead() 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.setListeners(new StepListener[] { new SkipListenerSupport() {
|
||||
@Override
|
||||
public void onSkipInRead(Throwable t) {
|
||||
throw new RuntimeException("oops");
|
||||
}
|
||||
} });
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
try {
|
||||
step.execute(stepExecution);
|
||||
fail("Expected SkipListenerFailedException.");
|
||||
}
|
||||
catch (SkipListenerFailedException e) {
|
||||
assertEquals("oops", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
assertEquals(1, stepExecution.getSkipCount());
|
||||
assertEquals(1, stepExecution.getReadSkipCount().intValue());
|
||||
assertEquals(0, stepExecution.getWriteSkipCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSkipListenerFailsOnWrite() 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.setListeners(new StepListener[] { new SkipListenerSupport() {
|
||||
@Override
|
||||
public void onSkipInWrite(Object item, Throwable t) {
|
||||
throw new RuntimeException("oops");
|
||||
}
|
||||
} });
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
|
||||
try {
|
||||
step.execute(stepExecution);
|
||||
fail("Expected SkipListenerFailedException.");
|
||||
}
|
||||
catch (SkipListenerFailedException e) {
|
||||
assertEquals("oops", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
assertEquals(1, stepExecution.getSkipCount());
|
||||
assertEquals(0, stepExecution.getReadSkipCount().intValue());
|
||||
assertEquals(1, stepExecution.getWriteSkipCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check items causing errors are skipped as expected.
|
||||
*/
|
||||
@@ -383,7 +462,7 @@ public class SkipLimitStepFactoryBeanTests extends TestCase {
|
||||
|
||||
public void clear() throws ClearFailedException {
|
||||
for (int i = flushIndex + 1; i < written.size(); i++) {
|
||||
written.remove(written.size()-1);
|
||||
written.remove(written.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.step.skip;
|
||||
|
||||
import org.springframework.batch.core.listener.AbstractDoubleExceptionTests;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SkipListenerFailedExceptionTests extends AbstractDoubleExceptionTests {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.listener.AbstractDoubleExceptionTests#getException(java.lang.String, java.lang.RuntimeException, java.lang.Throwable)
|
||||
*/
|
||||
@Override
|
||||
public Exception getException(String msg, RuntimeException cause, Throwable e) throws Exception {
|
||||
return new SkipListenerFailedException(msg, cause, e);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user