BATCH-1396: added step scope to retry and fixed bugs
This commit is contained in:
@@ -29,6 +29,7 @@ import org.junit.Test;
|
||||
import org.springframework.batch.classify.SubclassClassifier;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
|
||||
import org.springframework.batch.core.step.skip.SkipPolicy;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.support.CompositeItemStream;
|
||||
@@ -37,11 +38,13 @@ import org.springframework.batch.retry.listener.RetryListenerSupport;
|
||||
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.beans.PropertyAccessorUtils;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.CannotSerializeTransactionException;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.DeadlockLoserDataAccessException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
@@ -68,11 +71,32 @@ public class ChunkElementParserTests {
|
||||
@Test
|
||||
public void testCommitIntervalLateBinding() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementCommitIntervalParserTests-context.xml");
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementLateBindingParserTests-context.xml");
|
||||
Step step = (Step) context.getBean("s1", Step.class);
|
||||
assertNotNull("Step not parsed", step);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipAndRetryAttributes() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementSkipAndRetryAttributeParserTests-context.xml");
|
||||
Step step = (Step) context.getBean("s1", Step.class);
|
||||
assertNotNull("Step not parsed", step);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalSkipAndRetryAttributes() throws Exception {
|
||||
try {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementIllegalSkipAndRetryAttributeParserTests-context.xml");
|
||||
Step step = (Step) context.getBean("s1", Step.class);
|
||||
assertNotNull("Step not parsed", step);
|
||||
fail("Expected BeanDefinitionParsingException");
|
||||
} catch (BeanDefinitionParsingException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetryPolicyAttribute() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
@@ -98,19 +122,18 @@ public class ChunkElementParserTests {
|
||||
public void testSkipPolicyAttribute() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementSkipPolicyParserTests-context.xml");
|
||||
Map<Class<? extends Throwable>, Boolean> skippable = getSkippableExceptionClasses("s1", context);
|
||||
assertEquals(2, skippable.size());
|
||||
containsClassified(skippable, NullPointerException.class, true);
|
||||
containsClassified(skippable, ArithmeticException.class, true);
|
||||
SkipPolicy policy = getSkipPolicy("s1", context);
|
||||
assertTrue(policy.shouldSkip(new NullPointerException(), 0));
|
||||
assertTrue(policy.shouldSkip(new ArithmeticException(), 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipPolicyElement() throws Exception {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/ChunkElementSkipPolicyParserTests-context.xml");
|
||||
Map<Class<? extends Throwable>, Boolean> skippable = getSkippableExceptionClasses("s2", context);
|
||||
assertEquals(1, skippable.size());
|
||||
containsClassified(skippable, ArithmeticException.class, true);
|
||||
SkipPolicy policy = getSkipPolicy("s2", context);
|
||||
assertFalse(policy.shouldSkip(new NullPointerException(), 0));
|
||||
assertTrue(policy.shouldSkip(new ArithmeticException(), 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,6 +187,7 @@ public class ChunkElementParserTests {
|
||||
@Test
|
||||
public void testInheritSkippable() throws Exception {
|
||||
Map<Class<? extends Throwable>, Boolean> skippable = getSkippableExceptionClasses("s1", getContext());
|
||||
System.err.println(skippable);
|
||||
assertEquals(5, skippable.size());
|
||||
containsClassified(skippable, NullPointerException.class, true);
|
||||
containsClassified(skippable, ArithmeticException.class, true);
|
||||
@@ -175,9 +199,9 @@ public class ChunkElementParserTests {
|
||||
public void testInheritSkippableWithNoMerge() throws Exception {
|
||||
Map<Class<? extends Throwable>, Boolean> skippable = getSkippableExceptionClasses("s2", getContext());
|
||||
assertEquals(3, skippable.size());
|
||||
containsClassified(skippable, NullPointerException.class, true);
|
||||
containsClassified(skippable, IllegalArgumentException.class, true);
|
||||
assertFalse(skippable.containsKey(ArithmeticException.class));
|
||||
containsClassified(skippable, CannotAcquireLockException.class, false);
|
||||
containsClassified(skippable, ConcurrencyFailureException.class, false);
|
||||
assertFalse(skippable.containsKey(DeadlockLoserDataAccessException.class));
|
||||
}
|
||||
|
||||
@@ -244,6 +268,11 @@ public class ChunkElementParserTests {
|
||||
"skippableExceptionClassifier");
|
||||
}
|
||||
|
||||
private SkipPolicy getSkipPolicy(String stepName,
|
||||
ApplicationContext ctx) throws Exception {
|
||||
return (SkipPolicy) getNestedPathInStep(stepName, ctx, "tasklet.chunkProvider.skipPolicy");
|
||||
}
|
||||
|
||||
private Map<Class<? extends Throwable>, Boolean> getRetryableExceptionClasses(String stepName,
|
||||
ApplicationContext ctx) throws Exception {
|
||||
return getNestedExceptionMap(stepName, ctx,
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.item.FatalSkippableException;
|
||||
import org.springframework.batch.core.step.item.FatalRuntimeException;
|
||||
import org.springframework.batch.core.step.item.ForceRollbackForWriteSkipException;
|
||||
import org.springframework.batch.core.step.item.SkippableException;
|
||||
import org.springframework.batch.core.step.item.SkippableRuntimeException;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
@@ -428,9 +429,11 @@ public class StepParserTests {
|
||||
skippable.put(SkippableException.class, true);
|
||||
skippable.put(FatalRuntimeException.class, false);
|
||||
skippable.put(FatalSkippableException.class, false);
|
||||
skippable.put(ForceRollbackForWriteSkipException.class, true);
|
||||
Map<Class<? extends Throwable>, Boolean> retryable = new HashMap<Class<? extends Throwable>, Boolean>();
|
||||
retryable.put(DeadlockLoserDataAccessException.class, true);
|
||||
retryable.put(FatalSkippableException.class, true);
|
||||
retryable.put(ForceRollbackForWriteSkipException.class, true);
|
||||
List<Class<? extends ItemStream>> streams = Arrays.asList(CompositeItemStream.class, TestReader.class);
|
||||
List<Class<? extends RetryListener>> retryListeners = Arrays.asList(RetryListenerSupport.class,
|
||||
DummyRetryListener.class);
|
||||
@@ -464,8 +467,10 @@ public class StepParserTests {
|
||||
Map<Class<? extends Throwable>, Boolean> skippable = new HashMap<Class<? extends Throwable>, Boolean>();
|
||||
skippable.put(SkippableException.class, true);
|
||||
skippable.put(FatalSkippableException.class, false);
|
||||
skippable.put(ForceRollbackForWriteSkipException.class, true);
|
||||
Map<Class<? extends Throwable>, Boolean> retryable = new HashMap<Class<? extends Throwable>, Boolean>();
|
||||
retryable.put(FatalSkippableException.class, true);
|
||||
retryable.put(ForceRollbackForWriteSkipException.class, true);
|
||||
List<Class<CompositeItemStream>> streams = Arrays.asList(CompositeItemStream.class);
|
||||
List<Class<DummyRetryListener>> retryListeners = Arrays.asList(DummyRetryListener.class);
|
||||
List<Class<CompositeStepExecutionListener>> stepListeners = Arrays.asList(CompositeStepExecutionListener.class);
|
||||
@@ -495,8 +500,8 @@ public class StepParserTests {
|
||||
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) ctx
|
||||
.getBean("&stepWithListsOverrideWithEmpty");
|
||||
|
||||
assertEquals(0, getExceptionMap(fb, "skippableExceptionClasses").size());
|
||||
assertEquals(0, getExceptionMap(fb, "retryableExceptionClasses").size());
|
||||
assertEquals(1, getExceptionMap(fb, "skippableExceptionClasses").size());
|
||||
assertEquals(1, getExceptionMap(fb, "retryableExceptionClasses").size());
|
||||
assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length);
|
||||
assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length);
|
||||
assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length);
|
||||
|
||||
Reference in New Issue
Block a user