/*
* Copyright 2008-2012 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.junit.Test;
import org.springframework.retry.ExhaustedRetryException;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryState;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.DefaultRetryState;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class BatchRetryTemplateTests {
@SuppressWarnings("serial")
private static class RecoverableException extends Exception {
public RecoverableException(String message) {
super(message);
}
}
private int count = 0;
private List<String> outputs = new ArrayList<String>();
@Test
public void testSuccessfulAttempt() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
String result = template.execute(new RetryCallback<String, Exception>() {
@Override
public String doWithRetry(RetryContext context) throws Exception {
assertTrue("Wrong context type: " + context.getClass().getSimpleName(), context.getClass()
.getSimpleName().contains("Batch"));
return "2";
}
}, Arrays.<RetryState> asList(new DefaultRetryState("1")));
assertEquals("2", result);
}
@Test
public void testUnSuccessfulAttemptAndRetry() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
RetryCallback<String[], Exception> retryCallback = new RetryCallback<String[], Exception>() {
@Override
public String[] doWithRetry(RetryContext context) throws Exception {
assertEquals(count, context.getRetryCount());
if (count++ == 0) {
throw new RecoverableException("Recoverable");
}
return new String[] { "a", "b" };
}
};
List<RetryState> states = Arrays.<RetryState> asList(new DefaultRetryState("1"), new DefaultRetryState("2"));
try {
template.execute(retryCallback, states);
fail("Expected RecoverableException");
}
catch (RecoverableException e) {
assertEquals("Recoverable", e.getMessage());
}
String[] result = template.execute(retryCallback, states);
assertEquals("[a, b]", Arrays.toString(result));
}
@Test(expected = ExhaustedRetryException.class)
public void testExhaustedRetry() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[], Exception> retryCallback = new RetryCallback<String[], Exception>() {
@Override
public String[] doWithRetry(RetryContext context) throws Exception {
if (count++ < 2) {
throw new RecoverableException("Recoverable");
}
return outputs.toArray(new String[0]);
}
};
outputs = Arrays.asList("a", "b");
try {
template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
fail("Expected RecoverableException");
}
catch (RecoverableException e) {
assertEquals("Recoverable", e.getMessage());
}
outputs = Arrays.asList("a", "c");
template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
}
@Test
public void testExhaustedRetryAfterShuffle() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[], Exception> retryCallback = new RetryCallback<String[], Exception>() {
@Override
public String[] doWithRetry(RetryContext context) throws Exception {
if (count++ < 1) {
throw new RecoverableException("Recoverable");
}
return outputs.toArray(new String[0]);
}
};
outputs = Arrays.asList("a", "b");
try {
template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
fail("Expected RecoverableException");
}
catch (RecoverableException e) {
assertEquals("Recoverable", e.getMessage());
}
outputs = Arrays.asList("b", "c");
try {
template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
fail("Expected ExhaustedRetryException");
}
catch (ExhaustedRetryException e) {
}
// "c" is not tarred with same brush as "b" because it was never
// processed on account of the exhausted retry
outputs = Arrays.asList("d", "c");
String[] result = template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
assertEquals("[d, c]", Arrays.toString(result));
// "a" is still marked as a failure from the first chunk
outputs = Arrays.asList("a", "e");
try {
template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
fail("Expected ExhaustedRetryException");
}
catch (ExhaustedRetryException e) {
}
outputs = Arrays.asList("e", "f");
result = template.execute(retryCallback, BatchRetryTemplate.createState(outputs));
assertEquals("[e, f]", Arrays.toString(result));
}
@Test
public void testExhaustedRetryWithRecovery() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[], Exception> retryCallback = new RetryCallback<String[], Exception>() {
@Override
public String[] doWithRetry(RetryContext context) throws Exception {
if (count++ < 2) {
throw new RecoverableException("Recoverable");
}
return outputs.toArray(new String[0]);
}
};
RecoveryCallback<String[]> recoveryCallback = new RecoveryCallback<String[]>() {
@Override
public String[] recover(RetryContext context) throws Exception {
List<String> recovered = new ArrayList<String>();
for (String item : outputs) {
recovered.add("r:" + item);
}
return recovered.toArray(new String[0]);
}
};
outputs = Arrays.asList("a", "b");
try {
template.execute(retryCallback, recoveryCallback, BatchRetryTemplate.createState(outputs));
fail("Expected RecoverableException");
}
catch (RecoverableException e) {
assertEquals("Recoverable", e.getMessage());
}
outputs = Arrays.asList("b", "c");
String[] result = template.execute(retryCallback, recoveryCallback, BatchRetryTemplate.createState(outputs));
assertEquals("[r:b, r:c]", Arrays.toString(result));
}
}